diff --git a/.changelog/unreleased/breaking-changes/1193-multi-version-tendermint.md b/.changelog/unreleased/breaking-changes/1193-multi-version-tendermint.md new file mode 100644 index 000000000..cda523977 --- /dev/null +++ b/.changelog/unreleased/breaking-changes/1193-multi-version-tendermint.md @@ -0,0 +1,16 @@ +- [`tendermint`] Version-specific definitions for ABCI `Request` and `Response` + enums under `v0_34::abci` and `v0_37::abci`, containing only the method variants + present in each of the respective protocol versions. + `Request` and `Response` defined under `v0_37` are re-exported under + the non-versioned `abci` module name, but the `SetOption` variant is not present + in these latest versions of the enums. + ([#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)) +- [`tendermint-abci`] Change the frame length encoding in the ABCI wire protocol + to unsigned varint, to correspond to the changes in Tendermint Core 0.37. + No compatibility with 0.34 is provided at the moment. + ([#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)) +- [`tendermint-rpc`] Changed the signature of `WebSocketClient::new_with_config` + to accept a `WebSocketConfig` struct value rather than an `Option`. + ([#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)) +- [`tendermint-proto`] The `serializers::evidence` module has been made private. + ([#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)) diff --git a/.changelog/unreleased/enhancements/1193-multi-version-tendermint.md b/.changelog/unreleased/enhancements/1193-multi-version-tendermint.md new file mode 100644 index 000000000..617491b14 --- /dev/null +++ b/.changelog/unreleased/enhancements/1193-multi-version-tendermint.md @@ -0,0 +1,21 @@ +- [`tendermint-proto`] Generate prost bindings for Tendermint 0.34 and 0.37 side by side. + The version-specific structs are placed under the `tendermint::v0_34` and + `tendermint::v0_37` module namespaces, respectively. The names under + `tendermint::v0_37` are also re-exported under `tendermint`. + ([#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)) +- [`tendermint`] New and updated ABCI domain types for Tendermint Core v0.37 + ([#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)). +- [`tendermint`] Protobuf conversions provided for both `v0_34` and `v0_37` + versions of the generated [`tendermint-proto`] structs, where applicable. + ([#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)). +- [`tendermint-rpc`] Introduce `client::CompatMode`, enumerating protocol + compatibility modes specifying the RPC data encoding used by the client. + An `HttpClient` can be created with a selected mode specified in the new + `builder` API, or have the mode changed afterwards (usually after + version discovery) by the added `set_compat_mode` method. + For `WebSocketClient`, the mode can only be specified at creation via the new + `builder` API. + ([#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)) +- [`tendermint-abci`] Port ABCI application support to 0.37 Tendermint Core API. + No legacy support for 0.34 is provided at the moment. + ([#1193](https://github.com/informalsystems/tendermint-rs/pull/1193)). diff --git a/abci/src/application.rs b/abci/src/application.rs index 193307832..6fd532b7c 100644 --- a/abci/src/application.rs +++ b/abci/src/application.rs @@ -5,14 +5,15 @@ pub mod echo; #[cfg(feature = "kvstore-app")] pub mod kvstore; -use tendermint_proto::abci::{ - request::Value, response, Request, RequestApplySnapshotChunk, RequestBeginBlock, - RequestCheckTx, RequestDeliverTx, RequestEcho, RequestEndBlock, RequestInfo, RequestInitChain, - RequestLoadSnapshotChunk, RequestOfferSnapshot, RequestQuery, Response, - ResponseApplySnapshotChunk, ResponseBeginBlock, ResponseCheckTx, ResponseCommit, - ResponseDeliverTx, ResponseEcho, ResponseEndBlock, ResponseFlush, ResponseInfo, - ResponseInitChain, ResponseListSnapshots, ResponseLoadSnapshotChunk, ResponseOfferSnapshot, - ResponseQuery, +use tendermint_proto::v0_37::abci::{ + request::Value, response, response_process_proposal, Request, RequestApplySnapshotChunk, + RequestBeginBlock, RequestCheckTx, RequestDeliverTx, RequestEcho, RequestEndBlock, RequestInfo, + RequestInitChain, RequestLoadSnapshotChunk, RequestOfferSnapshot, RequestPrepareProposal, + RequestProcessProposal, RequestQuery, Response, ResponseApplySnapshotChunk, ResponseBeginBlock, + ResponseCheckTx, ResponseCommit, ResponseDeliverTx, ResponseEcho, ResponseEndBlock, + ResponseFlush, ResponseInfo, ResponseInitChain, ResponseListSnapshots, + ResponseLoadSnapshotChunk, ResponseOfferSnapshot, ResponsePrepareProposal, + ResponseProcessProposal, ResponseQuery, }; /// An ABCI application. @@ -98,6 +99,54 @@ pub trait Application: Send + Clone + 'static { ) -> ResponseApplySnapshotChunk { Default::default() } + + /// A stage where the application can modify the list of transactions + /// in the preliminary proposal. + /// + /// The default implementation implements the required behavior in a + /// very naive way, removing transactions off the end of the list + /// until the limit on the total size of the transaction is met as + /// specified in the `max_tx_bytes` field of the request, or there are + /// no more transactions. It's up to the application to implement + /// more elaborate removal strategies. + /// + /// This method is introduced in ABCI++. + fn prepare_proposal(&self, request: RequestPrepareProposal) -> ResponsePrepareProposal { + // Per the ABCI++ spec: if the size of RequestPrepareProposal.txs is + // greater than RequestPrepareProposal.max_tx_bytes, the Application + // MUST remove transactions to ensure that the + // RequestPrepareProposal.max_tx_bytes limit is respected by those + // transactions returned in ResponsePrepareProposal.txs. + let RequestPrepareProposal { + mut txs, + max_tx_bytes, + .. + } = request; + let max_tx_bytes: usize = max_tx_bytes.try_into().unwrap_or(0); + let mut total_tx_bytes: usize = txs + .iter() + .map(|tx| tx.len()) + .fold(0, |acc, len| acc.saturating_add(len)); + while total_tx_bytes > max_tx_bytes { + if let Some(tx) = txs.pop() { + total_tx_bytes = total_tx_bytes.saturating_sub(tx.len()); + } else { + break; + } + } + ResponsePrepareProposal { txs } + } + + /// A stage where the application can accept or reject the proposed block. + /// + /// The default implementation returns the status value of `ACCEPT`. + /// + /// This method is introduced in ABCI++. + fn process_proposal(&self, _request: RequestProcessProposal) -> ResponseProcessProposal { + ResponseProcessProposal { + status: response_process_proposal::ProposalStatus::Accept as i32, + } + } } /// Provides a mechanism for the [`Server`] to execute incoming requests while @@ -134,7 +183,12 @@ impl RequestDispatcher for A { Value::ApplySnapshotChunk(req) => { response::Value::ApplySnapshotChunk(self.apply_snapshot_chunk(req)) }, - Value::SetOption(_) => response::Value::SetOption(Default::default()), + Value::PrepareProposal(req) => { + response::Value::PrepareProposal(self.prepare_proposal(req)) + }, + Value::ProcessProposal(req) => { + response::Value::ProcessProposal(self.process_proposal(req)) + }, }), } } diff --git a/abci/src/application/kvstore.rs b/abci/src/application/kvstore.rs index a662c4681..f322e1d0b 100644 --- a/abci/src/application/kvstore.rs +++ b/abci/src/application/kvstore.rs @@ -6,7 +6,7 @@ use std::{ }; use bytes::BytesMut; -use tendermint_proto::abci::{ +use tendermint_proto::v0_37::abci::{ Event, EventAttribute, RequestCheckTx, RequestDeliverTx, RequestInfo, RequestQuery, ResponseCheckTx, ResponseCommit, ResponseDeliverTx, ResponseInfo, ResponseQuery, }; @@ -199,18 +199,18 @@ impl Application for KeyValueStoreApp { r#type: "app".to_string(), attributes: vec![ EventAttribute { - key: "key".to_string().into_bytes().into(), - value: key.to_string().into_bytes().into(), + key: "key".to_owned(), + value: key.to_owned(), index: true, }, EventAttribute { - key: "index_key".to_string().into_bytes().into(), - value: "index is working".to_string().into_bytes().into(), + key: "index_key".to_owned(), + value: "index is working".to_owned(), index: true, }, EventAttribute { - key: "noindex_key".to_string().into_bytes().into(), - value: "index is working".to_string().into_bytes().into(), + key: "noindex_key".to_owned(), + value: "index is working".to_owned(), index: false, }, ], diff --git a/abci/src/client.rs b/abci/src/client.rs index cbb039ec2..6fdb1de75 100644 --- a/abci/src/client.rs +++ b/abci/src/client.rs @@ -2,14 +2,14 @@ use std::net::{TcpStream, ToSocketAddrs}; -use tendermint_proto::abci::{ +use tendermint_proto::v0_37::abci::{ request, response, Request, RequestApplySnapshotChunk, RequestBeginBlock, RequestCheckTx, RequestCommit, RequestDeliverTx, RequestEcho, RequestEndBlock, RequestFlush, RequestInfo, RequestInitChain, RequestListSnapshots, RequestLoadSnapshotChunk, RequestOfferSnapshot, - RequestQuery, RequestSetOption, ResponseApplySnapshotChunk, ResponseBeginBlock, - ResponseCheckTx, ResponseCommit, ResponseDeliverTx, ResponseEcho, ResponseEndBlock, - ResponseFlush, ResponseInfo, ResponseInitChain, ResponseListSnapshots, - ResponseLoadSnapshotChunk, ResponseOfferSnapshot, ResponseQuery, ResponseSetOption, + RequestQuery, ResponseApplySnapshotChunk, ResponseBeginBlock, ResponseCheckTx, ResponseCommit, + ResponseDeliverTx, ResponseEcho, ResponseEndBlock, ResponseFlush, ResponseInfo, + ResponseInitChain, ResponseListSnapshots, ResponseLoadSnapshotChunk, ResponseOfferSnapshot, + ResponseQuery, }; use crate::{codec::ClientCodec, Error}; @@ -113,15 +113,6 @@ impl Client { perform!(self, Commit, RequestCommit {}) } - /// Request that the application set an option to a particular value. - /// - /// This request lacks specification and should not be used. - /// It will be removed in Tendermint Core v0.37. - #[deprecated(note = "The set_option ABCI method will be removed in Tendermint Core v0.37")] - pub fn set_option(&mut self, req: RequestSetOption) -> Result { - perform!(self, SetOption, req) - } - /// Used during state sync to discover available snapshots on peers. pub fn list_snapshots(&mut self) -> Result { perform!(self, ListSnapshots, RequestListSnapshots {}) diff --git a/abci/src/codec.rs b/abci/src/codec.rs index ce85acd24..6542a066d 100644 --- a/abci/src/codec.rs +++ b/abci/src/codec.rs @@ -11,7 +11,7 @@ use std::{ use bytes::{Buf, BufMut, BytesMut}; use prost::Message; -use tendermint_proto::abci::{Request, Response}; +use tendermint_proto::v0_37::abci::{Request, Response}; use crate::error::Error; @@ -130,7 +130,7 @@ where message.encode(&mut buf).map_err(Error::encode)?; let buf = buf.freeze(); - encode_varint(buf.len() as u64, &mut dst); + prost::encoding::encode_varint(buf.len() as u64, &mut dst); dst.put(buf); Ok(()) } @@ -142,11 +142,11 @@ where { let src_len = src.len(); let mut tmp = src.clone().freeze(); - let encoded_len = match decode_varint(&mut tmp) { + let encoded_len = match prost::encoding::decode_varint(&mut tmp) { Ok(len) => len, // We've potentially only received a partial length delimiter Err(_) if src_len <= MAX_VARINT_LENGTH => return Ok(None), - Err(e) => return Err(e), + Err(e) => return Err(Error::decode(e)), }; let remaining = tmp.remaining() as u64; if remaining < encoded_len { @@ -164,14 +164,3 @@ where Ok(Some(res)) } } - -// encode_varint and decode_varint will be removed once -// https://github.com/tendermint/tendermint/issues/5783 lands in Tendermint. -pub fn encode_varint(val: u64, mut buf: &mut B) { - prost::encoding::encode_varint(val << 1, &mut buf); -} - -pub fn decode_varint(mut buf: &mut B) -> Result { - let len = prost::encoding::decode_varint(&mut buf).map_err(Error::decode)?; - Ok(len >> 1) -} diff --git a/abci/src/error.rs b/abci/src/error.rs index dcdbb7e17..72b875d0e 100644 --- a/abci/src/error.rs +++ b/abci/src/error.rs @@ -1,7 +1,7 @@ //! tendermint-abci errors use flex_error::{define_error, DisplayError}; -use tendermint_proto::abci::response::Value; +use tendermint_proto::v0_37::abci::response::Value; define_error! { Error { diff --git a/abci/tests/echo_app.rs b/abci/tests/echo_app.rs index f0306099b..c2f07895b 100644 --- a/abci/tests/echo_app.rs +++ b/abci/tests/echo_app.rs @@ -3,7 +3,7 @@ #[cfg(all(feature = "client", feature = "echo-app"))] mod echo_app_integration { use tendermint_abci::{ClientBuilder, EchoApp, ServerBuilder}; - use tendermint_proto::abci::RequestEcho; + use tendermint_proto::v0_37::abci::RequestEcho; #[test] fn echo() { diff --git a/abci/tests/kvstore_app.rs b/abci/tests/kvstore_app.rs index 05c821483..998f167be 100644 --- a/abci/tests/kvstore_app.rs +++ b/abci/tests/kvstore_app.rs @@ -5,7 +5,7 @@ mod kvstore_app_integration { use std::thread; use tendermint_abci::{ClientBuilder, KeyValueStoreApp, ServerBuilder}; - use tendermint_proto::abci::{RequestDeliverTx, RequestEcho, RequestQuery}; + use tendermint_proto::v0_37::abci::{RequestDeliverTx, RequestEcho, RequestQuery}; #[test] fn happy_path() { diff --git a/light-client/src/supervisor.rs b/light-client/src/supervisor.rs index 07de1ec78..6653b1551 100644 --- a/light-client/src/supervisor.rs +++ b/light-client/src/supervisor.rs @@ -1,7 +1,7 @@ //! Supervisor and Handle implementation. use crossbeam_channel as channel; -use tendermint::evidence::{ConflictingHeadersEvidence, Evidence}; +use tendermint::evidence::Evidence; use crate::{ errors::Error, @@ -284,19 +284,15 @@ impl Supervisor { } /// Report the given evidence of a fork. + // TODO: rework to supply LightClientAttackEvidence data fn report_evidence( &mut self, provider: PeerId, - primary: &LightBlock, - witness: &LightBlock, + _primary: &LightBlock, + _witness: &LightBlock, ) -> Result<(), Error> { - let evidence = ConflictingHeadersEvidence::new( - primary.signed_header.clone(), - witness.signed_header.clone(), - ); - self.evidence_reporter - .report(Evidence::ConflictingHeaders(Box::new(evidence)), provider) + .report(Evidence::LightClientAttackEvidence, provider) .map_err(Error::io)?; Ok(()) diff --git a/p2p/src/secret_connection.rs b/p2p/src/secret_connection.rs index 87cfd6042..68a6681be 100644 --- a/p2p/src/secret_connection.rs +++ b/p2p/src/secret_connection.rs @@ -19,7 +19,7 @@ use chacha20poly1305::{ use merlin::Transcript; use rand_core::OsRng; use subtle::ConstantTimeEq; -use tendermint_proto as proto; +use tendermint_proto::v0_37 as proto; use tendermint_std_ext::TryClone; use x25519_dalek::{EphemeralSecret, PublicKey as EphemeralPublic}; diff --git a/p2p/src/secret_connection/amino_types.rs b/p2p/src/secret_connection/amino_types.rs index 8a69fa6eb..938418f90 100644 --- a/p2p/src/secret_connection/amino_types.rs +++ b/p2p/src/secret_connection/amino_types.rs @@ -2,7 +2,7 @@ use core::convert::TryFrom; use prost_derive::Message; -use tendermint_proto as proto; +use tendermint_proto::v0_37 as proto; use crate::error::Error; @@ -36,7 +36,7 @@ impl AuthSigMessage { } } -impl TryFrom for tendermint_proto::p2p::AuthSigMessage { +impl TryFrom for proto::p2p::AuthSigMessage { type Error = Error; fn try_from(amino_msg: AuthSigMessage) -> Result { diff --git a/p2p/src/secret_connection/protocol.rs b/p2p/src/secret_connection/protocol.rs index d6d8201f8..d15d90f29 100644 --- a/p2p/src/secret_connection/protocol.rs +++ b/p2p/src/secret_connection/protocol.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; use prost::Message as _; -use tendermint_proto as proto; +use tendermint_proto::v0_37 as proto; use x25519_dalek::PublicKey as EphemeralPublic; #[cfg(feature = "amino")] diff --git a/proto/src/prost/tendermint.abci.rs b/proto/src/prost/v0_34/tendermint.abci.rs similarity index 65% rename from proto/src/prost/tendermint.abci.rs rename to proto/src/prost/v0_34/tendermint.abci.rs index 8e03b04e8..240575c56 100644 --- a/proto/src/prost/tendermint.abci.rs +++ b/proto/src/prost/v0_34/tendermint.abci.rs @@ -1,378 +1,413 @@ -// This file is copied from -// NOTE: When using custom types, mind the warnings. -// - -// ---------------------------------------- -// Request types - +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Request { - #[prost(oneof="request::Value", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15")] + #[prost( + oneof = "request::Value", + tags = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15" + )] pub value: ::core::option::Option, } /// Nested message and enum types in `Request`. pub mod request { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Value { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] Echo(super::RequestEcho), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] Flush(super::RequestFlush), - #[prost(message, tag="3")] + #[prost(message, tag = "3")] Info(super::RequestInfo), - #[prost(message, tag="4")] + #[prost(message, tag = "4")] SetOption(super::RequestSetOption), - #[prost(message, tag="5")] + #[prost(message, tag = "5")] InitChain(super::RequestInitChain), - #[prost(message, tag="6")] + #[prost(message, tag = "6")] Query(super::RequestQuery), - #[prost(message, tag="7")] + #[prost(message, tag = "7")] BeginBlock(super::RequestBeginBlock), - #[prost(message, tag="8")] + #[prost(message, tag = "8")] CheckTx(super::RequestCheckTx), - #[prost(message, tag="9")] + #[prost(message, tag = "9")] DeliverTx(super::RequestDeliverTx), - #[prost(message, tag="10")] + #[prost(message, tag = "10")] EndBlock(super::RequestEndBlock), - #[prost(message, tag="11")] + #[prost(message, tag = "11")] Commit(super::RequestCommit), - #[prost(message, tag="12")] + #[prost(message, tag = "12")] ListSnapshots(super::RequestListSnapshots), - #[prost(message, tag="13")] + #[prost(message, tag = "13")] OfferSnapshot(super::RequestOfferSnapshot), - #[prost(message, tag="14")] + #[prost(message, tag = "14")] LoadSnapshotChunk(super::RequestLoadSnapshotChunk), - #[prost(message, tag="15")] + #[prost(message, tag = "15")] ApplySnapshotChunk(super::RequestApplySnapshotChunk), } } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestEcho { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub message: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct RequestFlush { -} +pub struct RequestFlush {} +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestInfo { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub version: ::prost::alloc::string::String, - #[prost(uint64, tag="2")] + #[prost(uint64, tag = "2")] pub block_version: u64, - #[prost(uint64, tag="3")] + #[prost(uint64, tag = "3")] pub p2p_version: u64, } /// nondeterministic +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestSetOption { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub key: ::prost::alloc::string::String, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub value: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestInitChain { - #[prost(message, optional, tag="1")] - pub time: ::core::option::Option, - #[prost(string, tag="2")] + #[prost(message, optional, tag = "1")] + pub time: ::core::option::Option, + #[prost(string, tag = "2")] pub chain_id: ::prost::alloc::string::String, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub consensus_params: ::core::option::Option, - #[prost(message, repeated, tag="4")] + #[prost(message, repeated, tag = "4")] pub validators: ::prost::alloc::vec::Vec, - #[prost(bytes="bytes", tag="5")] + #[prost(bytes = "bytes", tag = "5")] pub app_state_bytes: ::prost::bytes::Bytes, - #[prost(int64, tag="6")] + #[prost(int64, tag = "6")] pub initial_height: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestQuery { - #[prost(bytes="bytes", tag="1")] + #[prost(bytes = "bytes", tag = "1")] pub data: ::prost::bytes::Bytes, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub path: ::prost::alloc::string::String, - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] pub height: i64, - #[prost(bool, tag="4")] + #[prost(bool, tag = "4")] pub prove: bool, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestBeginBlock { - #[prost(bytes="bytes", tag="1")] + #[prost(bytes = "bytes", tag = "1")] pub hash: ::prost::bytes::Bytes, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub header: ::core::option::Option, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub last_commit_info: ::core::option::Option, - #[prost(message, repeated, tag="4")] + #[prost(message, repeated, tag = "4")] pub byzantine_validators: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestCheckTx { - #[prost(bytes="bytes", tag="1")] + #[prost(bytes = "bytes", tag = "1")] pub tx: ::prost::bytes::Bytes, - #[prost(enumeration="CheckTxType", tag="2")] + #[prost(enumeration = "CheckTxType", tag = "2")] pub r#type: i32, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestDeliverTx { - #[prost(bytes="bytes", tag="1")] + #[prost(bytes = "bytes", tag = "1")] pub tx: ::prost::bytes::Bytes, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestEndBlock { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct RequestCommit { -} +pub struct RequestCommit {} /// lists available snapshots +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct RequestListSnapshots { -} +pub struct RequestListSnapshots {} /// offers a snapshot to the application +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestOfferSnapshot { /// snapshot offered by peers - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub snapshot: ::core::option::Option, /// light client-verified app hash for snapshot height - #[prost(bytes="bytes", tag="2")] + #[prost(bytes = "bytes", tag = "2")] pub app_hash: ::prost::bytes::Bytes, } /// loads a snapshot chunk +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestLoadSnapshotChunk { - #[prost(uint64, tag="1")] + #[prost(uint64, tag = "1")] pub height: u64, - #[prost(uint32, tag="2")] + #[prost(uint32, tag = "2")] pub format: u32, - #[prost(uint32, tag="3")] + #[prost(uint32, tag = "3")] pub chunk: u32, } /// Applies a snapshot chunk +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestApplySnapshotChunk { - #[prost(uint32, tag="1")] + #[prost(uint32, tag = "1")] pub index: u32, - #[prost(bytes="bytes", tag="2")] + #[prost(bytes = "bytes", tag = "2")] pub chunk: ::prost::bytes::Bytes, - #[prost(string, tag="3")] + #[prost(string, tag = "3")] pub sender: ::prost::alloc::string::String, } -// ---------------------------------------- -// Response types - +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Response { - #[prost(oneof="response::Value", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16")] + #[prost( + oneof = "response::Value", + tags = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16" + )] pub value: ::core::option::Option, } /// Nested message and enum types in `Response`. pub mod response { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Value { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] Exception(super::ResponseException), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] Echo(super::ResponseEcho), - #[prost(message, tag="3")] + #[prost(message, tag = "3")] Flush(super::ResponseFlush), - #[prost(message, tag="4")] + #[prost(message, tag = "4")] Info(super::ResponseInfo), - #[prost(message, tag="5")] + #[prost(message, tag = "5")] SetOption(super::ResponseSetOption), - #[prost(message, tag="6")] + #[prost(message, tag = "6")] InitChain(super::ResponseInitChain), - #[prost(message, tag="7")] + #[prost(message, tag = "7")] Query(super::ResponseQuery), - #[prost(message, tag="8")] + #[prost(message, tag = "8")] BeginBlock(super::ResponseBeginBlock), - #[prost(message, tag="9")] + #[prost(message, tag = "9")] CheckTx(super::ResponseCheckTx), - #[prost(message, tag="10")] + #[prost(message, tag = "10")] DeliverTx(super::ResponseDeliverTx), - #[prost(message, tag="11")] + #[prost(message, tag = "11")] EndBlock(super::ResponseEndBlock), - #[prost(message, tag="12")] + #[prost(message, tag = "12")] Commit(super::ResponseCommit), - #[prost(message, tag="13")] + #[prost(message, tag = "13")] ListSnapshots(super::ResponseListSnapshots), - #[prost(message, tag="14")] + #[prost(message, tag = "14")] OfferSnapshot(super::ResponseOfferSnapshot), - #[prost(message, tag="15")] + #[prost(message, tag = "15")] LoadSnapshotChunk(super::ResponseLoadSnapshotChunk), - #[prost(message, tag="16")] + #[prost(message, tag = "16")] ApplySnapshotChunk(super::ResponseApplySnapshotChunk), } } /// nondeterministic +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseException { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub error: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseEcho { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub message: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct ResponseFlush { -} +pub struct ResponseFlush {} #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseInfo { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] #[serde(default)] pub data: ::prost::alloc::string::String, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] #[serde(default)] pub version: ::prost::alloc::string::String, - #[prost(uint64, tag="3")] + #[prost(uint64, tag = "3")] #[serde(with = "crate::serializers::from_str", default)] pub app_version: u64, - #[prost(int64, tag="4")] + #[prost(int64, tag = "4")] #[serde(with = "crate::serializers::from_str", default)] pub last_block_height: i64, - #[prost(bytes="bytes", tag="5")] + #[prost(bytes = "bytes", tag = "5")] #[serde(default)] #[serde(skip_serializing_if = "bytes::Bytes::is_empty")] pub last_block_app_hash: ::prost::bytes::Bytes, } /// nondeterministic +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseSetOption { - #[prost(uint32, tag="1")] + #[prost(uint32, tag = "1")] pub code: u32, /// bytes data = 2; - #[prost(string, tag="3")] + #[prost(string, tag = "3")] pub log: ::prost::alloc::string::String, - #[prost(string, tag="4")] + #[prost(string, tag = "4")] pub info: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseInitChain { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub consensus_params: ::core::option::Option, - #[prost(message, repeated, tag="2")] + #[prost(message, repeated, tag = "2")] pub validators: ::prost::alloc::vec::Vec, - #[prost(bytes="bytes", tag="3")] + #[prost(bytes = "bytes", tag = "3")] pub app_hash: ::prost::bytes::Bytes, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseQuery { - #[prost(uint32, tag="1")] + #[prost(uint32, tag = "1")] pub code: u32, /// bytes data = 2; // use "value" instead. /// /// nondeterministic - #[prost(string, tag="3")] + #[prost(string, tag = "3")] pub log: ::prost::alloc::string::String, /// nondeterministic - #[prost(string, tag="4")] + #[prost(string, tag = "4")] pub info: ::prost::alloc::string::String, - #[prost(int64, tag="5")] + #[prost(int64, tag = "5")] pub index: i64, - #[prost(bytes="bytes", tag="6")] + #[prost(bytes = "bytes", tag = "6")] pub key: ::prost::bytes::Bytes, - #[prost(bytes="bytes", tag="7")] + #[prost(bytes = "bytes", tag = "7")] pub value: ::prost::bytes::Bytes, - #[prost(message, optional, tag="8")] + #[prost(message, optional, tag = "8")] pub proof_ops: ::core::option::Option, - #[prost(int64, tag="9")] + #[prost(int64, tag = "9")] pub height: i64, - #[prost(string, tag="10")] + #[prost(string, tag = "10")] pub codespace: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseBeginBlock { - #[prost(message, repeated, tag="1")] + #[prost(message, repeated, tag = "1")] pub events: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseCheckTx { - #[prost(uint32, tag="1")] + #[prost(uint32, tag = "1")] pub code: u32, - #[prost(bytes="bytes", tag="2")] + #[prost(bytes = "bytes", tag = "2")] pub data: ::prost::bytes::Bytes, /// nondeterministic - #[prost(string, tag="3")] + #[prost(string, tag = "3")] pub log: ::prost::alloc::string::String, /// nondeterministic - #[prost(string, tag="4")] + #[prost(string, tag = "4")] pub info: ::prost::alloc::string::String, - #[prost(int64, tag="5")] + #[prost(int64, tag = "5")] pub gas_wanted: i64, - #[prost(int64, tag="6")] + #[prost(int64, tag = "6")] pub gas_used: i64, - #[prost(message, repeated, tag="7")] + #[prost(message, repeated, tag = "7")] pub events: ::prost::alloc::vec::Vec, - #[prost(string, tag="8")] + #[prost(string, tag = "8")] pub codespace: ::prost::alloc::string::String, - #[prost(string, tag="9")] + #[prost(string, tag = "9")] pub sender: ::prost::alloc::string::String, - #[prost(int64, tag="10")] + #[prost(int64, tag = "10")] pub priority: i64, /// mempool_error is set by Tendermint. /// ABCI applictions creating a ResponseCheckTX should not set mempool_error. - #[prost(string, tag="11")] + #[prost(string, tag = "11")] pub mempool_error: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseDeliverTx { - #[prost(uint32, tag="1")] + #[prost(uint32, tag = "1")] pub code: u32, - #[prost(bytes="bytes", tag="2")] + #[prost(bytes = "bytes", tag = "2")] pub data: ::prost::bytes::Bytes, /// nondeterministic - #[prost(string, tag="3")] + #[prost(string, tag = "3")] pub log: ::prost::alloc::string::String, /// nondeterministic - #[prost(string, tag="4")] + #[prost(string, tag = "4")] pub info: ::prost::alloc::string::String, - #[prost(int64, tag="5")] + #[prost(int64, tag = "5")] pub gas_wanted: i64, - #[prost(int64, tag="6")] + #[prost(int64, tag = "6")] pub gas_used: i64, /// nondeterministic - #[prost(message, repeated, tag="7")] + #[prost(message, repeated, tag = "7")] pub events: ::prost::alloc::vec::Vec, - #[prost(string, tag="8")] + #[prost(string, tag = "8")] pub codespace: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseEndBlock { - #[prost(message, repeated, tag="1")] + #[prost(message, repeated, tag = "1")] pub validator_updates: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub consensus_param_updates: ::core::option::Option, - #[prost(message, repeated, tag="3")] + #[prost(message, repeated, tag = "3")] pub events: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseCommit { /// reserve 1 - #[prost(bytes="bytes", tag="2")] + #[prost(bytes = "bytes", tag = "2")] pub data: ::prost::bytes::Bytes, - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] pub retain_height: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseListSnapshots { - #[prost(message, repeated, tag="1")] + #[prost(message, repeated, tag = "1")] pub snapshots: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseOfferSnapshot { - #[prost(enumeration="response_offer_snapshot::Result", tag="1")] + #[prost(enumeration = "response_offer_snapshot::Result", tag = "1")] pub result: i32, } /// Nested message and enum types in `ResponseOfferSnapshot`. pub mod response_offer_snapshot { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] #[repr(i32)] pub enum Result { /// Unknown result, abort all snapshot restoration @@ -405,25 +440,37 @@ pub mod response_offer_snapshot { } } } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseLoadSnapshotChunk { - #[prost(bytes="bytes", tag="1")] + #[prost(bytes = "bytes", tag = "1")] pub chunk: ::prost::bytes::Bytes, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseApplySnapshotChunk { - #[prost(enumeration="response_apply_snapshot_chunk::Result", tag="1")] + #[prost(enumeration = "response_apply_snapshot_chunk::Result", tag = "1")] pub result: i32, /// Chunks to refetch and reapply - #[prost(uint32, repeated, tag="2")] + #[prost(uint32, repeated, tag = "2")] pub refetch_chunks: ::prost::alloc::vec::Vec, /// Chunk senders to reject and ban - #[prost(string, repeated, tag="3")] + #[prost(string, repeated, tag = "3")] pub reject_senders: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } /// Nested message and enum types in `ResponseApplySnapshotChunk`. pub mod response_apply_snapshot_chunk { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] #[repr(i32)] pub enum Result { /// Unknown result, abort all snapshot restoration @@ -456,143 +503,145 @@ pub mod response_apply_snapshot_chunk { } } } -// ---------------------------------------- -// Misc. - /// ConsensusParams contains all consensus-relevant parameters /// that can be adjusted by the abci app +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ConsensusParams { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub block: ::core::option::Option, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub evidence: ::core::option::Option, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub validator: ::core::option::Option, - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub version: ::core::option::Option, } /// BlockParams contains limits on the block size. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockParams { /// Note: must be greater than 0 - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub max_bytes: i64, /// Note: must be greater or equal to -1 - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub max_gas: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LastCommitInfo { - #[prost(int32, tag="1")] + #[prost(int32, tag = "1")] pub round: i32, - #[prost(message, repeated, tag="2")] + #[prost(message, repeated, tag = "2")] pub votes: ::prost::alloc::vec::Vec, } /// Event allows application developers to attach additional information to /// ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. /// Later, transactions may be queried using these events. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Event { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub r#type: ::prost::alloc::string::String, - #[prost(message, repeated, tag="2")] + #[prost(message, repeated, tag = "2")] pub attributes: ::prost::alloc::vec::Vec, } /// EventAttribute is a single key-value pair, associated with an event. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EventAttribute { - #[prost(bytes="bytes", tag="1")] + #[prost(bytes = "bytes", tag = "1")] pub key: ::prost::bytes::Bytes, - #[prost(bytes="bytes", tag="2")] + #[prost(bytes = "bytes", tag = "2")] pub value: ::prost::bytes::Bytes, /// nondeterministic - #[prost(bool, tag="3")] + #[prost(bool, tag = "3")] pub index: bool, } /// TxResult contains results of executing the transaction. /// /// One usage is indexing transaction results. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TxResult { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, - #[prost(uint32, tag="2")] + #[prost(uint32, tag = "2")] pub index: u32, - #[prost(bytes="bytes", tag="3")] + #[prost(bytes = "bytes", tag = "3")] pub tx: ::prost::bytes::Bytes, - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub result: ::core::option::Option, } -// ---------------------------------------- -// Blockchain Types - /// Validator +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Validator { /// The first 20 bytes of SHA256(public key) - #[prost(bytes="bytes", tag="1")] + #[prost(bytes = "bytes", tag = "1")] pub address: ::prost::bytes::Bytes, /// PubKey pub_key = 2 \[(gogoproto.nullable)=false\]; /// /// The voting power - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] pub power: i64, } /// ValidatorUpdate +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ValidatorUpdate { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub pub_key: ::core::option::Option, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub power: i64, } /// VoteInfo +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct VoteInfo { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub validator: ::core::option::Option, - #[prost(bool, tag="2")] + #[prost(bool, tag = "2")] pub signed_last_block: bool, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Evidence { - #[prost(enumeration="EvidenceType", tag="1")] + #[prost(enumeration = "EvidenceType", tag = "1")] pub r#type: i32, /// The offending validator - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub validator: ::core::option::Option, /// The height when the offense occurred - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] pub height: i64, /// The corresponding time where the offense occurred - #[prost(message, optional, tag="4")] - pub time: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub time: ::core::option::Option, /// Total voting power of the validator set in case the ABCI application does /// not store historical validators. /// - #[prost(int64, tag="5")] + #[prost(int64, tag = "5")] pub total_voting_power: i64, } -// ---------------------------------------- -// State Sync Types - +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Snapshot { /// The height at which the snapshot was taken - #[prost(uint64, tag="1")] + #[prost(uint64, tag = "1")] pub height: u64, /// The application-specific snapshot format - #[prost(uint32, tag="2")] + #[prost(uint32, tag = "2")] pub format: u32, /// Number of chunks in the snapshot - #[prost(uint32, tag="3")] + #[prost(uint32, tag = "3")] pub chunks: u32, /// Arbitrary snapshot hash, equal only if identical - #[prost(bytes="bytes", tag="4")] + #[prost(bytes = "bytes", tag = "4")] pub hash: ::prost::bytes::Bytes, /// Arbitrary application metadata - #[prost(bytes="bytes", tag="5")] + #[prost(bytes = "bytes", tag = "5")] pub metadata: ::prost::bytes::Bytes, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] diff --git a/proto/src/prost/tendermint.blockchain.rs b/proto/src/prost/v0_34/tendermint.blockchain.rs similarity index 62% rename from proto/src/prost/tendermint.blockchain.rs rename to proto/src/prost/v0_34/tendermint.blockchain.rs index 492aa692e..4480ece49 100644 --- a/proto/src/prost/tendermint.blockchain.rs +++ b/proto/src/prost/v0_34/tendermint.blockchain.rs @@ -1,51 +1,57 @@ /// BlockRequest requests a block for a specific height +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockRequest { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, } /// NoBlockResponse informs the node that the peer does not have block at the requested height +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct NoBlockResponse { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, } /// BlockResponse returns block to the requested +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockResponse { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub block: ::core::option::Option, } /// StatusRequest requests the status of a peer. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct StatusRequest { -} +pub struct StatusRequest {} /// StatusResponse is a peer response to inform their status. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct StatusResponse { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub base: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Message { - #[prost(oneof="message::Sum", tags="1, 2, 3, 4, 5")] + #[prost(oneof = "message::Sum", tags = "1, 2, 3, 4, 5")] pub sum: ::core::option::Option, } /// Nested message and enum types in `Message`. pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Sum { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] BlockRequest(super::BlockRequest), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] NoBlockResponse(super::NoBlockResponse), - #[prost(message, tag="3")] + #[prost(message, tag = "3")] BlockResponse(super::BlockResponse), - #[prost(message, tag="4")] + #[prost(message, tag = "4")] StatusRequest(super::StatusRequest), - #[prost(message, tag="5")] + #[prost(message, tag = "5")] StatusResponse(super::StatusResponse), } } diff --git a/proto/src/prost/tendermint.consensus.rs b/proto/src/prost/v0_34/tendermint.consensus.rs similarity index 59% rename from proto/src/prost/tendermint.consensus.rs rename to proto/src/prost/v0_34/tendermint.consensus.rs index 1ada48be4..95237cc78 100644 --- a/proto/src/prost/tendermint.consensus.rs +++ b/proto/src/prost/v0_34/tendermint.consensus.rs @@ -1,184 +1,201 @@ /// NewRoundStep is sent for every step taken in the ConsensusState. /// For every height/round/step transition +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct NewRoundStep { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, - #[prost(int32, tag="2")] + #[prost(int32, tag = "2")] pub round: i32, - #[prost(uint32, tag="3")] + #[prost(uint32, tag = "3")] pub step: u32, - #[prost(int64, tag="4")] + #[prost(int64, tag = "4")] pub seconds_since_start_time: i64, - #[prost(int32, tag="5")] + #[prost(int32, tag = "5")] pub last_commit_round: i32, } /// NewValidBlock is sent when a validator observes a valid block B in some round r, /// i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r. /// In case the block is also committed, then IsCommit flag is set to true. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct NewValidBlock { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, - #[prost(int32, tag="2")] + #[prost(int32, tag = "2")] pub round: i32, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub block_part_set_header: ::core::option::Option, - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub block_parts: ::core::option::Option, - #[prost(bool, tag="5")] + #[prost(bool, tag = "5")] pub is_commit: bool, } /// Proposal is sent when a new block is proposed. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Proposal { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub proposal: ::core::option::Option, } /// ProposalPOL is sent when a previous proposal is re-proposed. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ProposalPol { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, - #[prost(int32, tag="2")] + #[prost(int32, tag = "2")] pub proposal_pol_round: i32, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub proposal_pol: ::core::option::Option, } /// BlockPart is sent when gossipping a piece of the proposed block. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockPart { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, - #[prost(int32, tag="2")] + #[prost(int32, tag = "2")] pub round: i32, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub part: ::core::option::Option, } /// Vote is sent when voting for a proposal (or lack thereof). +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Vote { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub vote: ::core::option::Option, } /// HasVote is sent to indicate that a particular vote has been received. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct HasVote { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, - #[prost(int32, tag="2")] + #[prost(int32, tag = "2")] pub round: i32, - #[prost(enumeration="super::types::SignedMsgType", tag="3")] + #[prost(enumeration = "super::types::SignedMsgType", tag = "3")] pub r#type: i32, - #[prost(int32, tag="4")] + #[prost(int32, tag = "4")] pub index: i32, } /// VoteSetMaj23 is sent to indicate that a given BlockID has seen +2/3 votes. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct VoteSetMaj23 { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, - #[prost(int32, tag="2")] + #[prost(int32, tag = "2")] pub round: i32, - #[prost(enumeration="super::types::SignedMsgType", tag="3")] + #[prost(enumeration = "super::types::SignedMsgType", tag = "3")] pub r#type: i32, - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub block_id: ::core::option::Option, } /// VoteSetBits is sent to communicate the bit-array of votes seen for the BlockID. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct VoteSetBits { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, - #[prost(int32, tag="2")] + #[prost(int32, tag = "2")] pub round: i32, - #[prost(enumeration="super::types::SignedMsgType", tag="3")] + #[prost(enumeration = "super::types::SignedMsgType", tag = "3")] pub r#type: i32, - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub block_id: ::core::option::Option, - #[prost(message, optional, tag="5")] + #[prost(message, optional, tag = "5")] pub votes: ::core::option::Option, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Message { - #[prost(oneof="message::Sum", tags="1, 2, 3, 4, 5, 6, 7, 8, 9")] + #[prost(oneof = "message::Sum", tags = "1, 2, 3, 4, 5, 6, 7, 8, 9")] pub sum: ::core::option::Option, } /// Nested message and enum types in `Message`. pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Sum { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] NewRoundStep(super::NewRoundStep), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] NewValidBlock(super::NewValidBlock), - #[prost(message, tag="3")] + #[prost(message, tag = "3")] Proposal(super::Proposal), - #[prost(message, tag="4")] + #[prost(message, tag = "4")] ProposalPol(super::ProposalPol), - #[prost(message, tag="5")] + #[prost(message, tag = "5")] BlockPart(super::BlockPart), - #[prost(message, tag="6")] + #[prost(message, tag = "6")] Vote(super::Vote), - #[prost(message, tag="7")] + #[prost(message, tag = "7")] HasVote(super::HasVote), - #[prost(message, tag="8")] + #[prost(message, tag = "8")] VoteSetMaj23(super::VoteSetMaj23), - #[prost(message, tag="9")] + #[prost(message, tag = "9")] VoteSetBits(super::VoteSetBits), } } /// MsgInfo are msgs from the reactor which may update the state +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgInfo { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub msg: ::core::option::Option, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub peer_id: ::prost::alloc::string::String, } /// TimeoutInfo internally generated messages which may update the state +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TimeoutInfo { - #[prost(message, optional, tag="1")] - pub duration: ::core::option::Option, - #[prost(int64, tag="2")] + #[prost(message, optional, tag = "1")] + pub duration: ::core::option::Option, + #[prost(int64, tag = "2")] pub height: i64, - #[prost(int32, tag="3")] + #[prost(int32, tag = "3")] pub round: i32, - #[prost(uint32, tag="4")] + #[prost(uint32, tag = "4")] pub step: u32, } /// EndHeight marks the end of the given height inside WAL. /// @internal used by scripts/wal2json util. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EndHeight { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub height: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct WalMessage { - #[prost(oneof="wal_message::Sum", tags="1, 2, 3, 4")] + #[prost(oneof = "wal_message::Sum", tags = "1, 2, 3, 4")] pub sum: ::core::option::Option, } /// Nested message and enum types in `WALMessage`. pub mod wal_message { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Sum { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] EventDataRoundState(super::super::types::EventDataRoundState), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] MsgInfo(super::MsgInfo), - #[prost(message, tag="3")] + #[prost(message, tag = "3")] TimeoutInfo(super::TimeoutInfo), - #[prost(message, tag="4")] + #[prost(message, tag = "4")] EndHeight(super::EndHeight), } } /// TimedWALMessage wraps WALMessage and adds Time for debugging purposes. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TimedWalMessage { - #[prost(message, optional, tag="1")] - pub time: ::core::option::Option, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "1")] + pub time: ::core::option::Option, + #[prost(message, optional, tag = "2")] pub msg: ::core::option::Option, } diff --git a/proto/src/prost/tendermint.crypto.rs b/proto/src/prost/v0_34/tendermint.crypto.rs similarity index 63% rename from proto/src/prost/tendermint.crypto.rs rename to proto/src/prost/v0_34/tendermint.crypto.rs index 0fac07973..fed646029 100644 --- a/proto/src/prost/tendermint.crypto.rs +++ b/proto/src/prost/v0_34/tendermint.crypto.rs @@ -1,73 +1,86 @@ #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Proof { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] #[serde(with = "crate::serializers::from_str")] pub total: i64, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] #[serde(with = "crate::serializers::from_str")] pub index: i64, - #[prost(bytes="vec", tag="3")] + #[prost(bytes = "vec", tag = "3")] #[serde(with = "crate::serializers::bytes::base64string")] pub leaf_hash: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", repeated, tag="4")] + #[prost(bytes = "vec", repeated, tag = "4")] #[serde(with = "crate::serializers::bytes::vec_base64string")] pub aunts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ValueOp { /// Encoded in ProofOp.Key. - #[prost(bytes="vec", tag="1")] + #[prost(bytes = "vec", tag = "1")] pub key: ::prost::alloc::vec::Vec, /// To encode in ProofOp.Data - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub proof: ::core::option::Option, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DominoOp { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub key: ::prost::alloc::string::String, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub input: ::prost::alloc::string::String, - #[prost(string, tag="3")] + #[prost(string, tag = "3")] pub output: ::prost::alloc::string::String, } /// ProofOp defines an operation used for calculating Merkle root /// The data could be arbitrary format, providing nessecary data /// for example neighbouring node hash +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ProofOp { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub r#type: ::prost::alloc::string::String, - #[prost(bytes="vec", tag="2")] + #[prost(bytes = "vec", tag = "2")] pub key: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="3")] + #[prost(bytes = "vec", tag = "3")] pub data: ::prost::alloc::vec::Vec, } /// ProofOps is Merkle proof defined by the list of ProofOps +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ProofOps { - #[prost(message, repeated, tag="1")] + #[prost(message, repeated, tag = "1")] pub ops: ::prost::alloc::vec::Vec, } /// PublicKey defines the keys available for use with Tendermint Validators #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PublicKey { - #[prost(oneof="public_key::Sum", tags="1, 2")] + #[prost(oneof = "public_key::Sum", tags = "1, 2")] pub sum: ::core::option::Option, } /// Nested message and enum types in `PublicKey`. pub mod public_key { #[derive(::serde::Deserialize, ::serde::Serialize)] #[serde(tag = "type", content = "value")] + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Sum { - #[prost(bytes, tag="1")] - #[serde(rename = "tendermint/PubKeyEd25519", with = "crate::serializers::bytes::base64string")] + #[prost(bytes, tag = "1")] + #[serde( + rename = "tendermint/PubKeyEd25519", + with = "crate::serializers::bytes::base64string" + )] Ed25519(::prost::alloc::vec::Vec), - #[prost(bytes, tag="2")] - #[serde(rename = "tendermint/PubKeySecp256k1", with = "crate::serializers::bytes::base64string")] + #[prost(bytes, tag = "2")] + #[serde( + rename = "tendermint/PubKeySecp256k1", + with = "crate::serializers::bytes::base64string" + )] Secp256k1(::prost::alloc::vec::Vec), } } diff --git a/proto/src/prost/tendermint.libs.bits.rs b/proto/src/prost/v0_34/tendermint.libs.bits.rs similarity index 60% rename from proto/src/prost/tendermint.libs.bits.rs rename to proto/src/prost/v0_34/tendermint.libs.bits.rs index 47eee3773..460876d21 100644 --- a/proto/src/prost/tendermint.libs.bits.rs +++ b/proto/src/prost/v0_34/tendermint.libs.bits.rs @@ -1,8 +1,9 @@ #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BitArray { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub bits: i64, - #[prost(uint64, repeated, tag="2")] + #[prost(uint64, repeated, tag = "2")] pub elems: ::prost::alloc::vec::Vec, } diff --git a/proto/src/prost/tendermint.mempool.rs b/proto/src/prost/v0_34/tendermint.mempool.rs similarity index 60% rename from proto/src/prost/tendermint.mempool.rs rename to proto/src/prost/v0_34/tendermint.mempool.rs index af22801ba..9fec1376b 100644 --- a/proto/src/prost/tendermint.mempool.rs +++ b/proto/src/prost/v0_34/tendermint.mempool.rs @@ -1,18 +1,21 @@ +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Txs { - #[prost(bytes="vec", repeated, tag="1")] + #[prost(bytes = "vec", repeated, tag = "1")] pub txs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Message { - #[prost(oneof="message::Sum", tags="1")] + #[prost(oneof = "message::Sum", tags = "1")] pub sum: ::core::option::Option, } /// Nested message and enum types in `Message`. pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Sum { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] Txs(super::Txs), } } diff --git a/proto/src/prost/tendermint.p2p.rs b/proto/src/prost/v0_34/tendermint.p2p.rs similarity index 56% rename from proto/src/prost/tendermint.p2p.rs rename to proto/src/prost/v0_34/tendermint.p2p.rs index 4dc33809c..bfaa808cb 100644 --- a/proto/src/prost/tendermint.p2p.rs +++ b/proto/src/prost/v0_34/tendermint.p2p.rs @@ -1,106 +1,117 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PacketPing {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PacketPong {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PacketMsg { + #[prost(int32, tag = "1")] + pub channel_id: i32, + #[prost(bool, tag = "2")] + pub eof: bool, + #[prost(bytes = "vec", tag = "3")] + pub data: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Packet { + #[prost(oneof = "packet::Sum", tags = "1, 2, 3")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `Packet`. +pub mod packet { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + PacketPing(super::PacketPing), + #[prost(message, tag = "2")] + PacketPong(super::PacketPong), + #[prost(message, tag = "3")] + PacketMsg(super::PacketMsg), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AuthSigMessage { + #[prost(message, optional, tag = "1")] + pub pub_key: ::core::option::Option, + #[prost(bytes = "vec", tag = "2")] + pub sig: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct NetAddress { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub id: ::prost::alloc::string::String, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub ip: ::prost::alloc::string::String, - #[prost(uint32, tag="3")] + #[prost(uint32, tag = "3")] pub port: u32, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ProtocolVersion { - #[prost(uint64, tag="1")] + #[prost(uint64, tag = "1")] pub p2p: u64, - #[prost(uint64, tag="2")] + #[prost(uint64, tag = "2")] pub block: u64, - #[prost(uint64, tag="3")] + #[prost(uint64, tag = "3")] pub app: u64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DefaultNodeInfo { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub protocol_version: ::core::option::Option, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub default_node_id: ::prost::alloc::string::String, - #[prost(string, tag="3")] + #[prost(string, tag = "3")] pub listen_addr: ::prost::alloc::string::String, - #[prost(string, tag="4")] + #[prost(string, tag = "4")] pub network: ::prost::alloc::string::String, - #[prost(string, tag="5")] + #[prost(string, tag = "5")] pub version: ::prost::alloc::string::String, - #[prost(bytes="vec", tag="6")] + #[prost(bytes = "vec", tag = "6")] pub channels: ::prost::alloc::vec::Vec, - #[prost(string, tag="7")] + #[prost(string, tag = "7")] pub moniker: ::prost::alloc::string::String, - #[prost(message, optional, tag="8")] + #[prost(message, optional, tag = "8")] pub other: ::core::option::Option, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DefaultNodeInfoOther { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub tx_index: ::prost::alloc::string::String, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub rpc_address: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct PacketPing { -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PacketPong { -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PacketMsg { - #[prost(int32, tag="1")] - pub channel_id: i32, - #[prost(bool, tag="2")] - pub eof: bool, - #[prost(bytes="vec", tag="3")] - pub data: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Packet { - #[prost(oneof="packet::Sum", tags="1, 2, 3")] - pub sum: ::core::option::Option, -} -/// Nested message and enum types in `Packet`. -pub mod packet { - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Sum { - #[prost(message, tag="1")] - PacketPing(super::PacketPing), - #[prost(message, tag="2")] - PacketPong(super::PacketPong), - #[prost(message, tag="3")] - PacketMsg(super::PacketMsg), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AuthSigMessage { - #[prost(message, optional, tag="1")] - pub pub_key: ::core::option::Option, - #[prost(bytes="vec", tag="2")] - pub sig: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PexRequest { -} +pub struct PexRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PexAddrs { - #[prost(message, repeated, tag="1")] + #[prost(message, repeated, tag = "1")] pub addrs: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Message { - #[prost(oneof="message::Sum", tags="1, 2")] + #[prost(oneof = "message::Sum", tags = "1, 2")] pub sum: ::core::option::Option, } /// Nested message and enum types in `Message`. pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Sum { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] PexRequest(super::PexRequest), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] PexAddrs(super::PexAddrs), } } diff --git a/proto/src/prost/tendermint.privval.rs b/proto/src/prost/v0_34/tendermint.privval.rs similarity index 71% rename from proto/src/prost/tendermint.privval.rs rename to proto/src/prost/v0_34/tendermint.privval.rs index 892a10bbf..1fae1cbee 100644 --- a/proto/src/prost/tendermint.privval.rs +++ b/proto/src/prost/v0_34/tendermint.privval.rs @@ -1,88 +1,97 @@ +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RemoteSignerError { - #[prost(int32, tag="1")] + #[prost(int32, tag = "1")] pub code: i32, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub description: ::prost::alloc::string::String, } /// PubKeyRequest requests the consensus public key from the remote signer. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PubKeyRequest { - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub chain_id: ::prost::alloc::string::String, } /// PubKeyResponse is a response message containing the public key. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PubKeyResponse { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub pub_key: ::core::option::Option, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub error: ::core::option::Option, } /// SignVoteRequest is a request to sign a vote +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SignVoteRequest { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub vote: ::core::option::Option, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub chain_id: ::prost::alloc::string::String, } /// SignedVoteResponse is a response containing a signed vote or an error +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SignedVoteResponse { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub vote: ::core::option::Option, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub error: ::core::option::Option, } /// SignProposalRequest is a request to sign a proposal +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SignProposalRequest { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub proposal: ::core::option::Option, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub chain_id: ::prost::alloc::string::String, } /// SignedProposalResponse is response containing a signed proposal or an error +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SignedProposalResponse { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub proposal: ::core::option::Option, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub error: ::core::option::Option, } /// PingRequest is a request to confirm that the connection is alive. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct PingRequest { -} +pub struct PingRequest {} /// PingResponse is a response to confirm that the connection is alive. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct PingResponse { -} +pub struct PingResponse {} +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Message { - #[prost(oneof="message::Sum", tags="1, 2, 3, 4, 5, 6, 7, 8")] + #[prost(oneof = "message::Sum", tags = "1, 2, 3, 4, 5, 6, 7, 8")] pub sum: ::core::option::Option, } /// Nested message and enum types in `Message`. pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Sum { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] PubKeyRequest(super::PubKeyRequest), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] PubKeyResponse(super::PubKeyResponse), - #[prost(message, tag="3")] + #[prost(message, tag = "3")] SignVoteRequest(super::SignVoteRequest), - #[prost(message, tag="4")] + #[prost(message, tag = "4")] SignedVoteResponse(super::SignedVoteResponse), - #[prost(message, tag="5")] + #[prost(message, tag = "5")] SignProposalRequest(super::SignProposalRequest), - #[prost(message, tag="6")] + #[prost(message, tag = "6")] SignedProposalResponse(super::SignedProposalResponse), - #[prost(message, tag="7")] + #[prost(message, tag = "7")] PingRequest(super::PingRequest), - #[prost(message, tag="8")] + #[prost(message, tag = "8")] PingResponse(super::PingResponse), } } diff --git a/proto/src/prost/tendermint.rpc.grpc.rs b/proto/src/prost/v0_34/tendermint.rpc.grpc.rs similarity index 55% rename from proto/src/prost/tendermint.rpc.grpc.rs rename to proto/src/prost/v0_34/tendermint.rpc.grpc.rs index 4739bccac..5630cb50c 100644 --- a/proto/src/prost/tendermint.rpc.grpc.rs +++ b/proto/src/prost/v0_34/tendermint.rpc.grpc.rs @@ -1,24 +1,20 @@ -// ---------------------------------------- -// Request types - +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct RequestPing { -} +pub struct RequestPing {} +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestBroadcastTx { - #[prost(bytes="vec", tag="1")] + #[prost(bytes = "vec", tag = "1")] pub tx: ::prost::alloc::vec::Vec, } -// ---------------------------------------- -// Response types - +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct ResponsePing { -} +pub struct ResponsePing {} +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseBroadcastTx { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub check_tx: ::core::option::Option, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub deliver_tx: ::core::option::Option, } diff --git a/proto/src/prost/tendermint.state.rs b/proto/src/prost/v0_34/tendermint.state.rs similarity index 68% rename from proto/src/prost/tendermint.state.rs rename to proto/src/prost/v0_34/tendermint.state.rs index c536f5df5..dd006a2c6 100644 --- a/proto/src/prost/tendermint.state.rs +++ b/proto/src/prost/v0_34/tendermint.state.rs @@ -1,85 +1,91 @@ /// ABCIResponses retains the responses /// of the various ABCI calls during block processing. /// It is persisted to disk for each height before calling Commit. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct AbciResponses { - #[prost(message, repeated, tag="1")] + #[prost(message, repeated, tag = "1")] pub deliver_txs: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub end_block: ::core::option::Option, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub begin_block: ::core::option::Option, } /// ValidatorsInfo represents the latest validator set, or the last height it changed +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ValidatorsInfo { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub validator_set: ::core::option::Option, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub last_height_changed: i64, } /// ConsensusParamsInfo represents the latest consensus params, or the last height it changed +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ConsensusParamsInfo { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub consensus_params: ::core::option::Option, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub last_height_changed: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct AbciResponsesInfo { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub abci_responses: ::core::option::Option, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub height: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Version { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub consensus: ::core::option::Option, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub software: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct State { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub version: ::core::option::Option, /// immutable - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub chain_id: ::prost::alloc::string::String, - #[prost(int64, tag="14")] + #[prost(int64, tag = "14")] pub initial_height: i64, /// LastBlockHeight=0 at genesis (ie. block(H=0) does not exist) - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] pub last_block_height: i64, - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub last_block_id: ::core::option::Option, - #[prost(message, optional, tag="5")] - pub last_block_time: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub last_block_time: ::core::option::Option, /// LastValidators is used to validate block.LastCommit. /// Validators are persisted to the database separately every time they change, /// so we can query for historical validator sets. /// Note that if s.LastBlockHeight causes a valset change, /// we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1 + 1 /// Extra +1 due to nextValSet delay. - #[prost(message, optional, tag="6")] + #[prost(message, optional, tag = "6")] pub next_validators: ::core::option::Option, - #[prost(message, optional, tag="7")] + #[prost(message, optional, tag = "7")] pub validators: ::core::option::Option, - #[prost(message, optional, tag="8")] + #[prost(message, optional, tag = "8")] pub last_validators: ::core::option::Option, - #[prost(int64, tag="9")] + #[prost(int64, tag = "9")] pub last_height_validators_changed: i64, /// Consensus parameters used for validating blocks. /// Changes returned by EndBlock and updated after Commit. - #[prost(message, optional, tag="10")] + #[prost(message, optional, tag = "10")] pub consensus_params: ::core::option::Option, - #[prost(int64, tag="11")] + #[prost(int64, tag = "11")] pub last_height_consensus_params_changed: i64, /// Merkle root of the results from executing prev block - #[prost(bytes="vec", tag="12")] + #[prost(bytes = "vec", tag = "12")] pub last_results_hash: ::prost::alloc::vec::Vec, /// the latest AppHash we've received from calling abci.Commit() - #[prost(bytes="vec", tag="13")] + #[prost(bytes = "vec", tag = "13")] pub app_hash: ::prost::alloc::vec::Vec, } diff --git a/proto/src/prost/tendermint.statesync.rs b/proto/src/prost/v0_34/tendermint.statesync.rs similarity index 52% rename from proto/src/prost/tendermint.statesync.rs rename to proto/src/prost/v0_34/tendermint.statesync.rs index 593bd0222..a2ad034e3 100644 --- a/proto/src/prost/tendermint.statesync.rs +++ b/proto/src/prost/v0_34/tendermint.statesync.rs @@ -1,57 +1,62 @@ +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Message { - #[prost(oneof="message::Sum", tags="1, 2, 3, 4")] + #[prost(oneof = "message::Sum", tags = "1, 2, 3, 4")] pub sum: ::core::option::Option, } /// Nested message and enum types in `Message`. pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Sum { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] SnapshotsRequest(super::SnapshotsRequest), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] SnapshotsResponse(super::SnapshotsResponse), - #[prost(message, tag="3")] + #[prost(message, tag = "3")] ChunkRequest(super::ChunkRequest), - #[prost(message, tag="4")] + #[prost(message, tag = "4")] ChunkResponse(super::ChunkResponse), } } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct SnapshotsRequest { -} +pub struct SnapshotsRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SnapshotsResponse { - #[prost(uint64, tag="1")] + #[prost(uint64, tag = "1")] pub height: u64, - #[prost(uint32, tag="2")] + #[prost(uint32, tag = "2")] pub format: u32, - #[prost(uint32, tag="3")] + #[prost(uint32, tag = "3")] pub chunks: u32, - #[prost(bytes="vec", tag="4")] + #[prost(bytes = "vec", tag = "4")] pub hash: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="5")] + #[prost(bytes = "vec", tag = "5")] pub metadata: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ChunkRequest { - #[prost(uint64, tag="1")] + #[prost(uint64, tag = "1")] pub height: u64, - #[prost(uint32, tag="2")] + #[prost(uint32, tag = "2")] pub format: u32, - #[prost(uint32, tag="3")] + #[prost(uint32, tag = "3")] pub index: u32, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ChunkResponse { - #[prost(uint64, tag="1")] + #[prost(uint64, tag = "1")] pub height: u64, - #[prost(uint32, tag="2")] + #[prost(uint32, tag = "2")] pub format: u32, - #[prost(uint32, tag="3")] + #[prost(uint32, tag = "3")] pub index: u32, - #[prost(bytes="vec", tag="4")] + #[prost(bytes = "vec", tag = "4")] pub chunk: ::prost::alloc::vec::Vec, - #[prost(bool, tag="5")] + #[prost(bool, tag = "5")] pub missing: bool, } diff --git a/proto/src/prost/tendermint.store.rs b/proto/src/prost/v0_34/tendermint.store.rs similarity index 51% rename from proto/src/prost/tendermint.store.rs rename to proto/src/prost/v0_34/tendermint.store.rs index a4c2799d9..98d20b0fc 100644 --- a/proto/src/prost/tendermint.store.rs +++ b/proto/src/prost/v0_34/tendermint.store.rs @@ -1,7 +1,8 @@ +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockStoreState { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub base: i64, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub height: i64, } diff --git a/proto/src/prost/tendermint.types.rs b/proto/src/prost/v0_34/tendermint.types.rs similarity index 69% rename from proto/src/prost/tendermint.types.rs rename to proto/src/prost/v0_34/tendermint.types.rs index 04368cf8f..66c081611 100644 --- a/proto/src/prost/tendermint.types.rs +++ b/proto/src/prost/v0_34/tendermint.types.rs @@ -1,256 +1,270 @@ #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ValidatorSet { - #[prost(message, repeated, tag="1")] + #[prost(message, repeated, tag = "1")] pub validators: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub proposer: ::core::option::Option, - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] pub total_voting_power: i64, } #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Validator { - #[prost(bytes="vec", tag="1")] + #[prost(bytes = "vec", tag = "1")] #[serde(with = "crate::serializers::bytes::hexstring")] pub address: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub pub_key: ::core::option::Option, - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] #[serde(alias = "power", with = "crate::serializers::from_str")] pub voting_power: i64, - #[prost(int64, tag="4")] + #[prost(int64, tag = "4")] #[serde(with = "crate::serializers::from_str", default)] pub proposer_priority: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SimpleValidator { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub pub_key: ::core::option::Option, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub voting_power: i64, } /// PartsetHeader #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PartSetHeader { - #[prost(uint32, tag="1")] + #[prost(uint32, tag = "1")] #[serde(with = "crate::serializers::part_set_header_total")] pub total: u32, - #[prost(bytes="vec", tag="2")] + #[prost(bytes = "vec", tag = "2")] #[serde(with = "crate::serializers::bytes::hexstring")] pub hash: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Part { - #[prost(uint32, tag="1")] + #[prost(uint32, tag = "1")] pub index: u32, - #[prost(bytes="vec", tag="2")] + #[prost(bytes = "vec", tag = "2")] pub bytes: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub proof: ::core::option::Option, } /// BlockID #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockId { - #[prost(bytes="vec", tag="1")] + #[prost(bytes = "vec", tag = "1")] #[serde(with = "crate::serializers::bytes::hexstring")] pub hash: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] #[serde(alias = "parts")] pub part_set_header: ::core::option::Option, } -// -------------------------------- - /// Header defines the structure of a Tendermint block header. #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Header { /// basic block info - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub version: ::core::option::Option, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub chain_id: ::prost::alloc::string::String, - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] #[serde(with = "crate::serializers::from_str")] pub height: i64, - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] #[serde(with = "crate::serializers::optional")] - pub time: ::core::option::Option, + pub time: ::core::option::Option, /// prev block info - #[prost(message, optional, tag="5")] + #[prost(message, optional, tag = "5")] pub last_block_id: ::core::option::Option, /// hashes of block data /// /// commit from validators from the last block - #[prost(bytes="vec", tag="6")] + #[prost(bytes = "vec", tag = "6")] #[serde(with = "crate::serializers::bytes::hexstring")] pub last_commit_hash: ::prost::alloc::vec::Vec, /// transactions - #[prost(bytes="vec", tag="7")] + #[prost(bytes = "vec", tag = "7")] #[serde(with = "crate::serializers::bytes::hexstring")] pub data_hash: ::prost::alloc::vec::Vec, /// hashes from the app output from the prev block /// /// validators for the current block - #[prost(bytes="vec", tag="8")] + #[prost(bytes = "vec", tag = "8")] #[serde(with = "crate::serializers::bytes::hexstring")] pub validators_hash: ::prost::alloc::vec::Vec, /// validators for the next block - #[prost(bytes="vec", tag="9")] + #[prost(bytes = "vec", tag = "9")] #[serde(with = "crate::serializers::bytes::hexstring")] pub next_validators_hash: ::prost::alloc::vec::Vec, /// consensus params for current block - #[prost(bytes="vec", tag="10")] + #[prost(bytes = "vec", tag = "10")] #[serde(with = "crate::serializers::bytes::hexstring")] pub consensus_hash: ::prost::alloc::vec::Vec, /// state after txs from the previous block - #[prost(bytes="vec", tag="11")] + #[prost(bytes = "vec", tag = "11")] #[serde(with = "crate::serializers::bytes::hexstring")] pub app_hash: ::prost::alloc::vec::Vec, /// root hash of all results from the txs from the previous block - #[prost(bytes="vec", tag="12")] + #[prost(bytes = "vec", tag = "12")] #[serde(with = "crate::serializers::bytes::hexstring")] pub last_results_hash: ::prost::alloc::vec::Vec, /// consensus info /// /// evidence included in the block - #[prost(bytes="vec", tag="13")] + #[prost(bytes = "vec", tag = "13")] #[serde(with = "crate::serializers::bytes::hexstring")] pub evidence_hash: ::prost::alloc::vec::Vec, /// original proposer of the block - #[prost(bytes="vec", tag="14")] + #[prost(bytes = "vec", tag = "14")] #[serde(with = "crate::serializers::bytes::hexstring")] pub proposer_address: ::prost::alloc::vec::Vec, } /// Data contains the set of transactions included in the block #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Data { /// Txs that will be applied by state @ block.Height+1. /// NOTE: not all txs here are valid. We're just agreeing on the order first. /// This means that block.AppHash does not include these txs. - #[prost(bytes="vec", repeated, tag="1")] + #[prost(bytes = "vec", repeated, tag = "1")] #[serde(with = "crate::serializers::txs")] pub txs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, } /// Vote represents a prevote, precommit, or commit vote from validators for /// consensus. #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Vote { - #[prost(enumeration="SignedMsgType", tag="1")] + #[prost(enumeration = "SignedMsgType", tag = "1")] pub r#type: i32, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] #[serde(with = "crate::serializers::from_str")] pub height: i64, - #[prost(int32, tag="3")] + #[prost(int32, tag = "3")] pub round: i32, /// zero if vote is nil. - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub block_id: ::core::option::Option, - #[prost(message, optional, tag="5")] + #[prost(message, optional, tag = "5")] #[serde(with = "crate::serializers::optional")] - pub timestamp: ::core::option::Option, - #[prost(bytes="vec", tag="6")] + pub timestamp: ::core::option::Option, + #[prost(bytes = "vec", tag = "6")] #[serde(with = "crate::serializers::bytes::hexstring")] pub validator_address: ::prost::alloc::vec::Vec, - #[prost(int32, tag="7")] + #[prost(int32, tag = "7")] pub validator_index: i32, - #[prost(bytes="vec", tag="8")] + #[prost(bytes = "vec", tag = "8")] #[serde(with = "crate::serializers::bytes::base64string")] pub signature: ::prost::alloc::vec::Vec, } /// Commit contains the evidence that a block was committed by a set of validators. #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Commit { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] #[serde(with = "crate::serializers::from_str")] pub height: i64, - #[prost(int32, tag="2")] + #[prost(int32, tag = "2")] pub round: i32, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub block_id: ::core::option::Option, - #[prost(message, repeated, tag="4")] + #[prost(message, repeated, tag = "4")] #[serde(with = "crate::serializers::nullable")] pub signatures: ::prost::alloc::vec::Vec, } /// CommitSig is a part of the Vote included in a Commit. #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CommitSig { - #[prost(enumeration="BlockIdFlag", tag="1")] + #[prost(enumeration = "BlockIdFlag", tag = "1")] pub block_id_flag: i32, - #[prost(bytes="vec", tag="2")] + #[prost(bytes = "vec", tag = "2")] #[serde(with = "crate::serializers::bytes::hexstring")] pub validator_address: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] #[serde(with = "crate::serializers::optional")] - pub timestamp: ::core::option::Option, - #[prost(bytes="vec", tag="4")] + pub timestamp: ::core::option::Option, + #[prost(bytes = "vec", tag = "4")] #[serde(with = "crate::serializers::bytes::base64string")] pub signature: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Proposal { - #[prost(enumeration="SignedMsgType", tag="1")] + #[prost(enumeration = "SignedMsgType", tag = "1")] pub r#type: i32, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub height: i64, - #[prost(int32, tag="3")] + #[prost(int32, tag = "3")] pub round: i32, - #[prost(int32, tag="4")] + #[prost(int32, tag = "4")] pub pol_round: i32, - #[prost(message, optional, tag="5")] + #[prost(message, optional, tag = "5")] pub block_id: ::core::option::Option, - #[prost(message, optional, tag="6")] - pub timestamp: ::core::option::Option, - #[prost(bytes="vec", tag="7")] + #[prost(message, optional, tag = "6")] + pub timestamp: ::core::option::Option, + #[prost(bytes = "vec", tag = "7")] pub signature: ::prost::alloc::vec::Vec, } #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SignedHeader { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub header: ::core::option::Option
, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub commit: ::core::option::Option, } #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LightBlock { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub signed_header: ::core::option::Option, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub validator_set: ::core::option::Option, } #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockMeta { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub block_id: ::core::option::Option, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] #[serde(with = "crate::serializers::from_str")] pub block_size: i64, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub header: ::core::option::Option
, - #[prost(int64, tag="4")] + #[prost(int64, tag = "4")] #[serde(with = "crate::serializers::from_str")] pub num_txs: i64, } /// TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TxProof { - #[prost(bytes="vec", tag="1")] + #[prost(bytes = "vec", tag = "1")] #[serde(with = "crate::serializers::bytes::hexstring")] pub root_hash: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="2")] + #[prost(bytes = "vec", tag = "2")] #[serde(with = "crate::serializers::bytes::base64string")] pub data: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub proof: ::core::option::Option, } /// BlockIdFlag indicates which BlcokID the signature is for @@ -302,220 +316,234 @@ impl SignedMsgType { } } } -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct EventDataRoundState { - #[prost(int64, tag="1")] - pub height: i64, - #[prost(int32, tag="2")] - pub round: i32, - #[prost(string, tag="3")] - pub step: ::prost::alloc::string::String, -} /// ConsensusParams contains consensus critical parameters that determine the /// validity of blocks. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ConsensusParams { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub block: ::core::option::Option, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub evidence: ::core::option::Option, - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub validator: ::core::option::Option, - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub version: ::core::option::Option, } /// BlockParams contains limits on the block size. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockParams { /// Max block size, in bytes. /// Note: must be greater than 0 - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub max_bytes: i64, /// Max gas per block. /// Note: must be greater or equal to -1 - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub max_gas: i64, /// Minimum time increment between consecutive blocks (in milliseconds) If the /// block header timestamp is ahead of the system clock, decrease this value. /// /// Not exposed to the application. - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] pub time_iota_ms: i64, } /// EvidenceParams determine how we handle evidence of malfeasance. #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EvidenceParams { /// Max age of evidence, in blocks. /// /// The basic formula for calculating this is: MaxAgeDuration / {average block /// time}. - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub max_age_num_blocks: i64, /// Max age of evidence, in time. /// /// It should correspond with an app's "unbonding period" or other similar /// mechanism for handling [Nothing-At-Stake /// attacks](). - #[prost(message, optional, tag="2")] - pub max_age_duration: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub max_age_duration: ::core::option::Option, /// This sets the maximum size of total evidence in bytes that can be committed in a single block. /// and should fall comfortably under the max block bytes. /// Default is 1048576 or 1MB - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] #[serde(with = "crate::serializers::from_str", default)] pub max_bytes: i64, } /// ValidatorParams restrict the public key types validators can use. /// NOTE: uses ABCI pubkey naming, not Amino names. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ValidatorParams { - #[prost(string, repeated, tag="1")] + #[prost(string, repeated, tag = "1")] pub pub_key_types: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } /// VersionParams contains the ABCI application version. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct VersionParams { - #[prost(uint64, tag="1")] + #[prost(uint64, tag = "1")] pub app_version: u64, } /// HashedParams is a subset of ConsensusParams. /// /// It is hashed into the Header.ConsensusHash. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct HashedParams { - #[prost(int64, tag="1")] + #[prost(int64, tag = "1")] pub block_max_bytes: i64, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub block_max_gas: i64, } -#[derive(::serde::Deserialize, ::serde::Serialize)] -#[serde(from = "crate::serializers::evidence::EvidenceVariant", into = "crate::serializers::evidence::EvidenceVariant")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EventDataRoundState { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int32, tag = "2")] + pub round: i32, + #[prost(string, tag = "3")] + pub step: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Evidence { - #[prost(oneof="evidence::Sum", tags="1, 2")] + #[prost(oneof = "evidence::Sum", tags = "1, 2")] pub sum: ::core::option::Option, } /// Nested message and enum types in `Evidence`. pub mod evidence { #[derive(::serde::Deserialize, ::serde::Serialize)] #[serde(tag = "type", content = "value")] - #[serde(from = "crate::serializers::evidence::EvidenceVariant", into = "crate::serializers::evidence::EvidenceVariant")] + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Sum { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] #[serde(rename = "tendermint/DuplicateVoteEvidence")] DuplicateVoteEvidence(super::DuplicateVoteEvidence), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] #[serde(rename = "tendermint/LightClientAttackEvidence")] LightClientAttackEvidence(super::LightClientAttackEvidence), } } /// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes. #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DuplicateVoteEvidence { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub vote_a: ::core::option::Option, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub vote_b: ::core::option::Option, - #[prost(int64, tag="3")] + #[prost(int64, tag = "3")] #[serde(alias = "TotalVotingPower", with = "crate::serializers::from_str")] pub total_voting_power: i64, - #[prost(int64, tag="4")] + #[prost(int64, tag = "4")] #[serde(alias = "ValidatorPower", with = "crate::serializers::from_str")] pub validator_power: i64, - #[prost(message, optional, tag="5")] + #[prost(message, optional, tag = "5")] #[serde(alias = "Timestamp")] - pub timestamp: ::core::option::Option, + pub timestamp: ::core::option::Option, } /// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client. #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct LightClientAttackEvidence { - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub conflicting_block: ::core::option::Option, - #[prost(int64, tag="2")] + #[prost(int64, tag = "2")] pub common_height: i64, - #[prost(message, repeated, tag="3")] + #[prost(message, repeated, tag = "3")] pub byzantine_validators: ::prost::alloc::vec::Vec, - #[prost(int64, tag="4")] + #[prost(int64, tag = "4")] pub total_voting_power: i64, - #[prost(message, optional, tag="5")] - pub timestamp: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub timestamp: ::core::option::Option, } #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EvidenceList { - #[prost(message, repeated, tag="1")] + #[prost(message, repeated, tag = "1")] #[serde(with = "crate::serializers::nullable")] pub evidence: ::prost::alloc::vec::Vec, } #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Block { + #[prost(message, optional, tag = "1")] + pub header: ::core::option::Option
, + #[prost(message, optional, tag = "2")] + pub data: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub evidence: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub last_commit: ::core::option::Option, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CanonicalBlockId { - #[prost(bytes="vec", tag="1")] + #[prost(bytes = "vec", tag = "1")] pub hash: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] #[serde(alias = "parts")] pub part_set_header: ::core::option::Option, } #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CanonicalPartSetHeader { - #[prost(uint32, tag="1")] + #[prost(uint32, tag = "1")] pub total: u32, - #[prost(bytes="vec", tag="2")] + #[prost(bytes = "vec", tag = "2")] pub hash: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CanonicalProposal { /// type alias for byte - #[prost(enumeration="SignedMsgType", tag="1")] + #[prost(enumeration = "SignedMsgType", tag = "1")] pub r#type: i32, /// canonicalization requires fixed size encoding here - #[prost(sfixed64, tag="2")] + #[prost(sfixed64, tag = "2")] pub height: i64, /// canonicalization requires fixed size encoding here - #[prost(sfixed64, tag="3")] + #[prost(sfixed64, tag = "3")] pub round: i64, - #[prost(int64, tag="4")] + #[prost(int64, tag = "4")] pub pol_round: i64, - #[prost(message, optional, tag="5")] + #[prost(message, optional, tag = "5")] pub block_id: ::core::option::Option, - #[prost(message, optional, tag="6")] - pub timestamp: ::core::option::Option, - #[prost(string, tag="7")] + #[prost(message, optional, tag = "6")] + pub timestamp: ::core::option::Option, + #[prost(string, tag = "7")] pub chain_id: ::prost::alloc::string::String, } #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CanonicalVote { /// type alias for byte - #[prost(enumeration="SignedMsgType", tag="1")] + #[prost(enumeration = "SignedMsgType", tag = "1")] pub r#type: i32, /// canonicalization requires fixed size encoding here - #[prost(sfixed64, tag="2")] + #[prost(sfixed64, tag = "2")] pub height: i64, /// canonicalization requires fixed size encoding here - #[prost(sfixed64, tag="3")] + #[prost(sfixed64, tag = "3")] pub round: i64, - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub block_id: ::core::option::Option, - #[prost(message, optional, tag="5")] - pub timestamp: ::core::option::Option, - #[prost(string, tag="6")] + #[prost(message, optional, tag = "5")] + pub timestamp: ::core::option::Option, + #[prost(string, tag = "6")] pub chain_id: ::prost::alloc::string::String, } -#[derive(::serde::Deserialize, ::serde::Serialize)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Block { - #[prost(message, optional, tag="1")] - pub header: ::core::option::Option
, - #[prost(message, optional, tag="2")] - pub data: ::core::option::Option, - #[prost(message, optional, tag="3")] - pub evidence: ::core::option::Option, - #[prost(message, optional, tag="4")] - pub last_commit: ::core::option::Option, -} diff --git a/proto/src/prost/tendermint.version.rs b/proto/src/prost/v0_34/tendermint.version.rs similarity index 77% rename from proto/src/prost/tendermint.version.rs rename to proto/src/prost/v0_34/tendermint.version.rs index bd1227266..8a77a26fc 100644 --- a/proto/src/prost/tendermint.version.rs +++ b/proto/src/prost/v0_34/tendermint.version.rs @@ -1,23 +1,25 @@ /// App includes the protocol and software version for the application. /// This information is included in ResponseInfo. The App.Protocol can be /// updated in ResponseEndBlock. +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct App { - #[prost(uint64, tag="1")] + #[prost(uint64, tag = "1")] pub protocol: u64, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub software: ::prost::alloc::string::String, } /// Consensus captures the consensus rules for processing a block in the blockchain, /// including all blockchain data structures and the rules of the application's /// state transition machine. #[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Consensus { - #[prost(uint64, tag="1")] + #[prost(uint64, tag = "1")] #[serde(with = "crate::serializers::from_str")] pub block: u64, - #[prost(uint64, tag="2")] + #[prost(uint64, tag = "2")] #[serde(with = "crate::serializers::from_str", default)] pub app: u64, } diff --git a/proto/src/prost/v0_37/tendermint.abci.rs b/proto/src/prost/v0_37/tendermint.abci.rs new file mode 100644 index 000000000..acccf14ad --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.abci.rs @@ -0,0 +1,757 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Request { + #[prost( + oneof = "request::Value", + tags = "1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17" + )] + pub value: ::core::option::Option, +} +/// Nested message and enum types in `Request`. +pub mod request { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Value { + #[prost(message, tag = "1")] + Echo(super::RequestEcho), + #[prost(message, tag = "2")] + Flush(super::RequestFlush), + #[prost(message, tag = "3")] + Info(super::RequestInfo), + #[prost(message, tag = "5")] + InitChain(super::RequestInitChain), + #[prost(message, tag = "6")] + Query(super::RequestQuery), + #[prost(message, tag = "7")] + BeginBlock(super::RequestBeginBlock), + #[prost(message, tag = "8")] + CheckTx(super::RequestCheckTx), + #[prost(message, tag = "9")] + DeliverTx(super::RequestDeliverTx), + #[prost(message, tag = "10")] + EndBlock(super::RequestEndBlock), + #[prost(message, tag = "11")] + Commit(super::RequestCommit), + #[prost(message, tag = "12")] + ListSnapshots(super::RequestListSnapshots), + #[prost(message, tag = "13")] + OfferSnapshot(super::RequestOfferSnapshot), + #[prost(message, tag = "14")] + LoadSnapshotChunk(super::RequestLoadSnapshotChunk), + #[prost(message, tag = "15")] + ApplySnapshotChunk(super::RequestApplySnapshotChunk), + #[prost(message, tag = "16")] + PrepareProposal(super::RequestPrepareProposal), + #[prost(message, tag = "17")] + ProcessProposal(super::RequestProcessProposal), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestEcho { + #[prost(string, tag = "1")] + pub message: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestFlush {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestInfo { + #[prost(string, tag = "1")] + pub version: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] + pub block_version: u64, + #[prost(uint64, tag = "3")] + pub p2p_version: u64, + #[prost(string, tag = "4")] + pub abci_version: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestInitChain { + #[prost(message, optional, tag = "1")] + pub time: ::core::option::Option, + #[prost(string, tag = "2")] + pub chain_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "3")] + pub consensus_params: ::core::option::Option, + #[prost(message, repeated, tag = "4")] + pub validators: ::prost::alloc::vec::Vec, + #[prost(bytes = "bytes", tag = "5")] + pub app_state_bytes: ::prost::bytes::Bytes, + #[prost(int64, tag = "6")] + pub initial_height: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestQuery { + #[prost(bytes = "bytes", tag = "1")] + pub data: ::prost::bytes::Bytes, + #[prost(string, tag = "2")] + pub path: ::prost::alloc::string::String, + #[prost(int64, tag = "3")] + pub height: i64, + #[prost(bool, tag = "4")] + pub prove: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestBeginBlock { + #[prost(bytes = "bytes", tag = "1")] + pub hash: ::prost::bytes::Bytes, + #[prost(message, optional, tag = "2")] + pub header: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub last_commit_info: ::core::option::Option, + #[prost(message, repeated, tag = "4")] + pub byzantine_validators: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestCheckTx { + #[prost(bytes = "bytes", tag = "1")] + pub tx: ::prost::bytes::Bytes, + #[prost(enumeration = "CheckTxType", tag = "2")] + pub r#type: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestDeliverTx { + #[prost(bytes = "bytes", tag = "1")] + pub tx: ::prost::bytes::Bytes, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestEndBlock { + #[prost(int64, tag = "1")] + pub height: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestCommit {} +/// lists available snapshots +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestListSnapshots {} +/// offers a snapshot to the application +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestOfferSnapshot { + /// snapshot offered by peers + #[prost(message, optional, tag = "1")] + pub snapshot: ::core::option::Option, + /// light client-verified app hash for snapshot height + #[prost(bytes = "bytes", tag = "2")] + pub app_hash: ::prost::bytes::Bytes, +} +/// loads a snapshot chunk +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestLoadSnapshotChunk { + #[prost(uint64, tag = "1")] + pub height: u64, + #[prost(uint32, tag = "2")] + pub format: u32, + #[prost(uint32, tag = "3")] + pub chunk: u32, +} +/// Applies a snapshot chunk +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestApplySnapshotChunk { + #[prost(uint32, tag = "1")] + pub index: u32, + #[prost(bytes = "bytes", tag = "2")] + pub chunk: ::prost::bytes::Bytes, + #[prost(string, tag = "3")] + pub sender: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestPrepareProposal { + /// the modified transactions cannot exceed this size. + #[prost(int64, tag = "1")] + pub max_tx_bytes: i64, + /// txs is an array of transactions that will be included in a block, + /// sent to the app for possible modifications. + #[prost(bytes = "bytes", repeated, tag = "2")] + pub txs: ::prost::alloc::vec::Vec<::prost::bytes::Bytes>, + #[prost(message, optional, tag = "3")] + pub local_last_commit: ::core::option::Option, + #[prost(message, repeated, tag = "4")] + pub misbehavior: ::prost::alloc::vec::Vec, + #[prost(int64, tag = "5")] + pub height: i64, + #[prost(message, optional, tag = "6")] + pub time: ::core::option::Option, + #[prost(bytes = "bytes", tag = "7")] + pub next_validators_hash: ::prost::bytes::Bytes, + /// address of the public key of the validator proposing the block. + #[prost(bytes = "bytes", tag = "8")] + pub proposer_address: ::prost::bytes::Bytes, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestProcessProposal { + #[prost(bytes = "bytes", repeated, tag = "1")] + pub txs: ::prost::alloc::vec::Vec<::prost::bytes::Bytes>, + #[prost(message, optional, tag = "2")] + pub proposed_last_commit: ::core::option::Option, + #[prost(message, repeated, tag = "3")] + pub misbehavior: ::prost::alloc::vec::Vec, + /// hash is the merkle root hash of the fields of the proposed block. + #[prost(bytes = "bytes", tag = "4")] + pub hash: ::prost::bytes::Bytes, + #[prost(int64, tag = "5")] + pub height: i64, + #[prost(message, optional, tag = "6")] + pub time: ::core::option::Option, + #[prost(bytes = "bytes", tag = "7")] + pub next_validators_hash: ::prost::bytes::Bytes, + /// address of the public key of the original proposer of the block. + #[prost(bytes = "bytes", tag = "8")] + pub proposer_address: ::prost::bytes::Bytes, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Response { + #[prost( + oneof = "response::Value", + tags = "1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18" + )] + pub value: ::core::option::Option, +} +/// Nested message and enum types in `Response`. +pub mod response { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Value { + #[prost(message, tag = "1")] + Exception(super::ResponseException), + #[prost(message, tag = "2")] + Echo(super::ResponseEcho), + #[prost(message, tag = "3")] + Flush(super::ResponseFlush), + #[prost(message, tag = "4")] + Info(super::ResponseInfo), + #[prost(message, tag = "6")] + InitChain(super::ResponseInitChain), + #[prost(message, tag = "7")] + Query(super::ResponseQuery), + #[prost(message, tag = "8")] + BeginBlock(super::ResponseBeginBlock), + #[prost(message, tag = "9")] + CheckTx(super::ResponseCheckTx), + #[prost(message, tag = "10")] + DeliverTx(super::ResponseDeliverTx), + #[prost(message, tag = "11")] + EndBlock(super::ResponseEndBlock), + #[prost(message, tag = "12")] + Commit(super::ResponseCommit), + #[prost(message, tag = "13")] + ListSnapshots(super::ResponseListSnapshots), + #[prost(message, tag = "14")] + OfferSnapshot(super::ResponseOfferSnapshot), + #[prost(message, tag = "15")] + LoadSnapshotChunk(super::ResponseLoadSnapshotChunk), + #[prost(message, tag = "16")] + ApplySnapshotChunk(super::ResponseApplySnapshotChunk), + #[prost(message, tag = "17")] + PrepareProposal(super::ResponsePrepareProposal), + #[prost(message, tag = "18")] + ProcessProposal(super::ResponseProcessProposal), + } +} +/// nondeterministic +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseException { + #[prost(string, tag = "1")] + pub error: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseEcho { + #[prost(string, tag = "1")] + pub message: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseFlush {} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseInfo { + #[prost(string, tag = "1")] + #[serde(default)] + pub data: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + #[serde(default)] + pub version: ::prost::alloc::string::String, + #[prost(uint64, tag = "3")] + #[serde(with = "crate::serializers::from_str", default)] + pub app_version: u64, + #[prost(int64, tag = "4")] + #[serde(with = "crate::serializers::from_str", default)] + pub last_block_height: i64, + #[prost(bytes = "bytes", tag = "5")] + #[serde(default)] + #[serde(skip_serializing_if = "bytes::Bytes::is_empty")] + pub last_block_app_hash: ::prost::bytes::Bytes, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseInitChain { + #[prost(message, optional, tag = "1")] + pub consensus_params: ::core::option::Option, + #[prost(message, repeated, tag = "2")] + pub validators: ::prost::alloc::vec::Vec, + #[prost(bytes = "bytes", tag = "3")] + pub app_hash: ::prost::bytes::Bytes, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseQuery { + #[prost(uint32, tag = "1")] + pub code: u32, + /// bytes data = 2; // use "value" instead. + /// + /// nondeterministic + #[prost(string, tag = "3")] + pub log: ::prost::alloc::string::String, + /// nondeterministic + #[prost(string, tag = "4")] + pub info: ::prost::alloc::string::String, + #[prost(int64, tag = "5")] + pub index: i64, + #[prost(bytes = "bytes", tag = "6")] + pub key: ::prost::bytes::Bytes, + #[prost(bytes = "bytes", tag = "7")] + pub value: ::prost::bytes::Bytes, + #[prost(message, optional, tag = "8")] + pub proof_ops: ::core::option::Option, + #[prost(int64, tag = "9")] + pub height: i64, + #[prost(string, tag = "10")] + pub codespace: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseBeginBlock { + #[prost(message, repeated, tag = "1")] + pub events: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseCheckTx { + #[prost(uint32, tag = "1")] + pub code: u32, + #[prost(bytes = "bytes", tag = "2")] + pub data: ::prost::bytes::Bytes, + /// nondeterministic + #[prost(string, tag = "3")] + pub log: ::prost::alloc::string::String, + /// nondeterministic + #[prost(string, tag = "4")] + pub info: ::prost::alloc::string::String, + #[prost(int64, tag = "5")] + pub gas_wanted: i64, + #[prost(int64, tag = "6")] + pub gas_used: i64, + #[prost(message, repeated, tag = "7")] + pub events: ::prost::alloc::vec::Vec, + #[prost(string, tag = "8")] + pub codespace: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub sender: ::prost::alloc::string::String, + #[prost(int64, tag = "10")] + pub priority: i64, + /// mempool_error is set by Tendermint. + /// ABCI applictions creating a ResponseCheckTX should not set mempool_error. + #[prost(string, tag = "11")] + pub mempool_error: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseDeliverTx { + #[prost(uint32, tag = "1")] + pub code: u32, + #[prost(bytes = "bytes", tag = "2")] + pub data: ::prost::bytes::Bytes, + /// nondeterministic + #[prost(string, tag = "3")] + pub log: ::prost::alloc::string::String, + /// nondeterministic + #[prost(string, tag = "4")] + pub info: ::prost::alloc::string::String, + #[prost(int64, tag = "5")] + pub gas_wanted: i64, + #[prost(int64, tag = "6")] + pub gas_used: i64, + /// nondeterministic + #[prost(message, repeated, tag = "7")] + pub events: ::prost::alloc::vec::Vec, + #[prost(string, tag = "8")] + pub codespace: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseEndBlock { + #[prost(message, repeated, tag = "1")] + pub validator_updates: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub consensus_param_updates: ::core::option::Option, + #[prost(message, repeated, tag = "3")] + pub events: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseCommit { + /// reserve 1 + #[prost(bytes = "bytes", tag = "2")] + pub data: ::prost::bytes::Bytes, + #[prost(int64, tag = "3")] + pub retain_height: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseListSnapshots { + #[prost(message, repeated, tag = "1")] + pub snapshots: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseOfferSnapshot { + #[prost(enumeration = "response_offer_snapshot::Result", tag = "1")] + pub result: i32, +} +/// Nested message and enum types in `ResponseOfferSnapshot`. +pub mod response_offer_snapshot { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Result { + /// Unknown result, abort all snapshot restoration + Unknown = 0, + /// Snapshot accepted, apply chunks + Accept = 1, + /// Abort all snapshot restoration + Abort = 2, + /// Reject this specific snapshot, try others + Reject = 3, + /// Reject all snapshots of this format, try others + RejectFormat = 4, + /// Reject all snapshots from the sender(s), try others + RejectSender = 5, + } + impl Result { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Result::Unknown => "UNKNOWN", + Result::Accept => "ACCEPT", + Result::Abort => "ABORT", + Result::Reject => "REJECT", + Result::RejectFormat => "REJECT_FORMAT", + Result::RejectSender => "REJECT_SENDER", + } + } + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseLoadSnapshotChunk { + #[prost(bytes = "bytes", tag = "1")] + pub chunk: ::prost::bytes::Bytes, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseApplySnapshotChunk { + #[prost(enumeration = "response_apply_snapshot_chunk::Result", tag = "1")] + pub result: i32, + /// Chunks to refetch and reapply + #[prost(uint32, repeated, tag = "2")] + pub refetch_chunks: ::prost::alloc::vec::Vec, + /// Chunk senders to reject and ban + #[prost(string, repeated, tag = "3")] + pub reject_senders: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +/// Nested message and enum types in `ResponseApplySnapshotChunk`. +pub mod response_apply_snapshot_chunk { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Result { + /// Unknown result, abort all snapshot restoration + Unknown = 0, + /// Chunk successfully accepted + Accept = 1, + /// Abort all snapshot restoration + Abort = 2, + /// Retry chunk (combine with refetch and reject) + Retry = 3, + /// Retry snapshot (combine with refetch and reject) + RetrySnapshot = 4, + /// Reject this snapshot, try others + RejectSnapshot = 5, + } + impl Result { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Result::Unknown => "UNKNOWN", + Result::Accept => "ACCEPT", + Result::Abort => "ABORT", + Result::Retry => "RETRY", + Result::RetrySnapshot => "RETRY_SNAPSHOT", + Result::RejectSnapshot => "REJECT_SNAPSHOT", + } + } + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponsePrepareProposal { + #[prost(bytes = "bytes", repeated, tag = "1")] + pub txs: ::prost::alloc::vec::Vec<::prost::bytes::Bytes>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseProcessProposal { + #[prost(enumeration = "response_process_proposal::ProposalStatus", tag = "1")] + pub status: i32, +} +/// Nested message and enum types in `ResponseProcessProposal`. +pub mod response_process_proposal { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum ProposalStatus { + Unknown = 0, + Accept = 1, + Reject = 2, + } + impl ProposalStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ProposalStatus::Unknown => "UNKNOWN", + ProposalStatus::Accept => "ACCEPT", + ProposalStatus::Reject => "REJECT", + } + } + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitInfo { + #[prost(int32, tag = "1")] + pub round: i32, + #[prost(message, repeated, tag = "2")] + pub votes: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExtendedCommitInfo { + /// The round at which the block proposer decided in the previous height. + #[prost(int32, tag = "1")] + pub round: i32, + /// List of validators' addresses in the last validator set with their voting + /// information, including vote extensions. + #[prost(message, repeated, tag = "2")] + pub votes: ::prost::alloc::vec::Vec, +} +/// Event allows application developers to attach additional information to +/// ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. +/// Later, transactions may be queried using these events. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Event { + #[prost(string, tag = "1")] + pub r#type: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "2")] + pub attributes: ::prost::alloc::vec::Vec, +} +/// EventAttribute is a single key-value pair, associated with an event. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EventAttribute { + #[prost(string, tag = "1")] + pub key: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub value: ::prost::alloc::string::String, + /// nondeterministic + #[prost(bool, tag = "3")] + pub index: bool, +} +/// TxResult contains results of executing the transaction. +/// +/// One usage is indexing transaction results. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TxResult { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(uint32, tag = "2")] + pub index: u32, + #[prost(bytes = "bytes", tag = "3")] + pub tx: ::prost::bytes::Bytes, + #[prost(message, optional, tag = "4")] + pub result: ::core::option::Option, +} +/// Validator +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Validator { + /// The first 20 bytes of SHA256(public key) + #[prost(bytes = "bytes", tag = "1")] + pub address: ::prost::bytes::Bytes, + /// PubKey pub_key = 2 \[(gogoproto.nullable)=false\]; + /// + /// The voting power + #[prost(int64, tag = "3")] + pub power: i64, +} +/// ValidatorUpdate +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValidatorUpdate { + #[prost(message, optional, tag = "1")] + pub pub_key: ::core::option::Option, + #[prost(int64, tag = "2")] + pub power: i64, +} +/// VoteInfo +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VoteInfo { + #[prost(message, optional, tag = "1")] + pub validator: ::core::option::Option, + #[prost(bool, tag = "2")] + pub signed_last_block: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExtendedVoteInfo { + #[prost(message, optional, tag = "1")] + pub validator: ::core::option::Option, + #[prost(bool, tag = "2")] + pub signed_last_block: bool, + /// Reserved for future use + #[prost(bytes = "bytes", tag = "3")] + pub vote_extension: ::prost::bytes::Bytes, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Misbehavior { + #[prost(enumeration = "MisbehaviorType", tag = "1")] + pub r#type: i32, + /// The offending validator + #[prost(message, optional, tag = "2")] + pub validator: ::core::option::Option, + /// The height when the offense occurred + #[prost(int64, tag = "3")] + pub height: i64, + /// The corresponding time where the offense occurred + #[prost(message, optional, tag = "4")] + pub time: ::core::option::Option, + /// Total voting power of the validator set in case the ABCI application does + /// not store historical validators. + /// + #[prost(int64, tag = "5")] + pub total_voting_power: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Snapshot { + /// The height at which the snapshot was taken + #[prost(uint64, tag = "1")] + pub height: u64, + /// The application-specific snapshot format + #[prost(uint32, tag = "2")] + pub format: u32, + /// Number of chunks in the snapshot + #[prost(uint32, tag = "3")] + pub chunks: u32, + /// Arbitrary snapshot hash, equal only if identical + #[prost(bytes = "bytes", tag = "4")] + pub hash: ::prost::bytes::Bytes, + /// Arbitrary application metadata + #[prost(bytes = "bytes", tag = "5")] + pub metadata: ::prost::bytes::Bytes, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum CheckTxType { + New = 0, + Recheck = 1, +} +impl CheckTxType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + CheckTxType::New => "NEW", + CheckTxType::Recheck => "RECHECK", + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum MisbehaviorType { + Unknown = 0, + DuplicateVote = 1, + LightClientAttack = 2, +} +impl MisbehaviorType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + MisbehaviorType::Unknown => "UNKNOWN", + MisbehaviorType::DuplicateVote => "DUPLICATE_VOTE", + MisbehaviorType::LightClientAttack => "LIGHT_CLIENT_ATTACK", + } + } +} diff --git a/proto/src/prost/v0_37/tendermint.blocksync.rs b/proto/src/prost/v0_37/tendermint.blocksync.rs new file mode 100644 index 000000000..4480ece49 --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.blocksync.rs @@ -0,0 +1,57 @@ +/// BlockRequest requests a block for a specific height +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockRequest { + #[prost(int64, tag = "1")] + pub height: i64, +} +/// NoBlockResponse informs the node that the peer does not have block at the requested height +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NoBlockResponse { + #[prost(int64, tag = "1")] + pub height: i64, +} +/// BlockResponse returns block to the requested +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockResponse { + #[prost(message, optional, tag = "1")] + pub block: ::core::option::Option, +} +/// StatusRequest requests the status of a peer. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StatusRequest {} +/// StatusResponse is a peer response to inform their status. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StatusResponse { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int64, tag = "2")] + pub base: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + #[prost(oneof = "message::Sum", tags = "1, 2, 3, 4, 5")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + BlockRequest(super::BlockRequest), + #[prost(message, tag = "2")] + NoBlockResponse(super::NoBlockResponse), + #[prost(message, tag = "3")] + BlockResponse(super::BlockResponse), + #[prost(message, tag = "4")] + StatusRequest(super::StatusRequest), + #[prost(message, tag = "5")] + StatusResponse(super::StatusResponse), + } +} diff --git a/proto/src/prost/v0_37/tendermint.consensus.rs b/proto/src/prost/v0_37/tendermint.consensus.rs new file mode 100644 index 000000000..95237cc78 --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.consensus.rs @@ -0,0 +1,201 @@ +/// NewRoundStep is sent for every step taken in the ConsensusState. +/// For every height/round/step transition +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NewRoundStep { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int32, tag = "2")] + pub round: i32, + #[prost(uint32, tag = "3")] + pub step: u32, + #[prost(int64, tag = "4")] + pub seconds_since_start_time: i64, + #[prost(int32, tag = "5")] + pub last_commit_round: i32, +} +/// NewValidBlock is sent when a validator observes a valid block B in some round r, +/// i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r. +/// In case the block is also committed, then IsCommit flag is set to true. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NewValidBlock { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int32, tag = "2")] + pub round: i32, + #[prost(message, optional, tag = "3")] + pub block_part_set_header: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub block_parts: ::core::option::Option, + #[prost(bool, tag = "5")] + pub is_commit: bool, +} +/// Proposal is sent when a new block is proposed. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Proposal { + #[prost(message, optional, tag = "1")] + pub proposal: ::core::option::Option, +} +/// ProposalPOL is sent when a previous proposal is re-proposed. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProposalPol { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int32, tag = "2")] + pub proposal_pol_round: i32, + #[prost(message, optional, tag = "3")] + pub proposal_pol: ::core::option::Option, +} +/// BlockPart is sent when gossipping a piece of the proposed block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockPart { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int32, tag = "2")] + pub round: i32, + #[prost(message, optional, tag = "3")] + pub part: ::core::option::Option, +} +/// Vote is sent when voting for a proposal (or lack thereof). +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Vote { + #[prost(message, optional, tag = "1")] + pub vote: ::core::option::Option, +} +/// HasVote is sent to indicate that a particular vote has been received. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HasVote { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int32, tag = "2")] + pub round: i32, + #[prost(enumeration = "super::types::SignedMsgType", tag = "3")] + pub r#type: i32, + #[prost(int32, tag = "4")] + pub index: i32, +} +/// VoteSetMaj23 is sent to indicate that a given BlockID has seen +2/3 votes. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VoteSetMaj23 { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int32, tag = "2")] + pub round: i32, + #[prost(enumeration = "super::types::SignedMsgType", tag = "3")] + pub r#type: i32, + #[prost(message, optional, tag = "4")] + pub block_id: ::core::option::Option, +} +/// VoteSetBits is sent to communicate the bit-array of votes seen for the BlockID. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VoteSetBits { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int32, tag = "2")] + pub round: i32, + #[prost(enumeration = "super::types::SignedMsgType", tag = "3")] + pub r#type: i32, + #[prost(message, optional, tag = "4")] + pub block_id: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub votes: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + #[prost(oneof = "message::Sum", tags = "1, 2, 3, 4, 5, 6, 7, 8, 9")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + NewRoundStep(super::NewRoundStep), + #[prost(message, tag = "2")] + NewValidBlock(super::NewValidBlock), + #[prost(message, tag = "3")] + Proposal(super::Proposal), + #[prost(message, tag = "4")] + ProposalPol(super::ProposalPol), + #[prost(message, tag = "5")] + BlockPart(super::BlockPart), + #[prost(message, tag = "6")] + Vote(super::Vote), + #[prost(message, tag = "7")] + HasVote(super::HasVote), + #[prost(message, tag = "8")] + VoteSetMaj23(super::VoteSetMaj23), + #[prost(message, tag = "9")] + VoteSetBits(super::VoteSetBits), + } +} +/// MsgInfo are msgs from the reactor which may update the state +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgInfo { + #[prost(message, optional, tag = "1")] + pub msg: ::core::option::Option, + #[prost(string, tag = "2")] + pub peer_id: ::prost::alloc::string::String, +} +/// TimeoutInfo internally generated messages which may update the state +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TimeoutInfo { + #[prost(message, optional, tag = "1")] + pub duration: ::core::option::Option, + #[prost(int64, tag = "2")] + pub height: i64, + #[prost(int32, tag = "3")] + pub round: i32, + #[prost(uint32, tag = "4")] + pub step: u32, +} +/// EndHeight marks the end of the given height inside WAL. +/// @internal used by scripts/wal2json util. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EndHeight { + #[prost(int64, tag = "1")] + pub height: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct WalMessage { + #[prost(oneof = "wal_message::Sum", tags = "1, 2, 3, 4")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `WALMessage`. +pub mod wal_message { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + EventDataRoundState(super::super::types::EventDataRoundState), + #[prost(message, tag = "2")] + MsgInfo(super::MsgInfo), + #[prost(message, tag = "3")] + TimeoutInfo(super::TimeoutInfo), + #[prost(message, tag = "4")] + EndHeight(super::EndHeight), + } +} +/// TimedWALMessage wraps WALMessage and adds Time for debugging purposes. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TimedWalMessage { + #[prost(message, optional, tag = "1")] + pub time: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub msg: ::core::option::Option, +} diff --git a/proto/src/prost/v0_37/tendermint.crypto.rs b/proto/src/prost/v0_37/tendermint.crypto.rs new file mode 100644 index 000000000..fed646029 --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.crypto.rs @@ -0,0 +1,86 @@ +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Proof { + #[prost(int64, tag = "1")] + #[serde(with = "crate::serializers::from_str")] + pub total: i64, + #[prost(int64, tag = "2")] + #[serde(with = "crate::serializers::from_str")] + pub index: i64, + #[prost(bytes = "vec", tag = "3")] + #[serde(with = "crate::serializers::bytes::base64string")] + pub leaf_hash: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", repeated, tag = "4")] + #[serde(with = "crate::serializers::bytes::vec_base64string")] + pub aunts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValueOp { + /// Encoded in ProofOp.Key. + #[prost(bytes = "vec", tag = "1")] + pub key: ::prost::alloc::vec::Vec, + /// To encode in ProofOp.Data + #[prost(message, optional, tag = "2")] + pub proof: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DominoOp { + #[prost(string, tag = "1")] + pub key: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub input: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub output: ::prost::alloc::string::String, +} +/// ProofOp defines an operation used for calculating Merkle root +/// The data could be arbitrary format, providing nessecary data +/// for example neighbouring node hash +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProofOp { + #[prost(string, tag = "1")] + pub r#type: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub key: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "3")] + pub data: ::prost::alloc::vec::Vec, +} +/// ProofOps is Merkle proof defined by the list of ProofOps +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProofOps { + #[prost(message, repeated, tag = "1")] + pub ops: ::prost::alloc::vec::Vec, +} +/// PublicKey defines the keys available for use with Tendermint Validators +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PublicKey { + #[prost(oneof = "public_key::Sum", tags = "1, 2")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `PublicKey`. +pub mod public_key { + #[derive(::serde::Deserialize, ::serde::Serialize)] + #[serde(tag = "type", content = "value")] + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(bytes, tag = "1")] + #[serde( + rename = "tendermint/PubKeyEd25519", + with = "crate::serializers::bytes::base64string" + )] + Ed25519(::prost::alloc::vec::Vec), + #[prost(bytes, tag = "2")] + #[serde( + rename = "tendermint/PubKeySecp256k1", + with = "crate::serializers::bytes::base64string" + )] + Secp256k1(::prost::alloc::vec::Vec), + } +} diff --git a/proto/src/prost/v0_37/tendermint.libs.bits.rs b/proto/src/prost/v0_37/tendermint.libs.bits.rs new file mode 100644 index 000000000..460876d21 --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.libs.bits.rs @@ -0,0 +1,9 @@ +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BitArray { + #[prost(int64, tag = "1")] + pub bits: i64, + #[prost(uint64, repeated, tag = "2")] + pub elems: ::prost::alloc::vec::Vec, +} diff --git a/proto/src/prost/v0_37/tendermint.mempool.rs b/proto/src/prost/v0_37/tendermint.mempool.rs new file mode 100644 index 000000000..9fec1376b --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.mempool.rs @@ -0,0 +1,21 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Txs { + #[prost(bytes = "vec", repeated, tag = "1")] + pub txs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + #[prost(oneof = "message::Sum", tags = "1")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + Txs(super::Txs), + } +} diff --git a/proto/src/prost/v0_37/tendermint.p2p.rs b/proto/src/prost/v0_37/tendermint.p2p.rs new file mode 100644 index 000000000..bfaa808cb --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.p2p.rs @@ -0,0 +1,117 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PacketPing {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PacketPong {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PacketMsg { + #[prost(int32, tag = "1")] + pub channel_id: i32, + #[prost(bool, tag = "2")] + pub eof: bool, + #[prost(bytes = "vec", tag = "3")] + pub data: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Packet { + #[prost(oneof = "packet::Sum", tags = "1, 2, 3")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `Packet`. +pub mod packet { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + PacketPing(super::PacketPing), + #[prost(message, tag = "2")] + PacketPong(super::PacketPong), + #[prost(message, tag = "3")] + PacketMsg(super::PacketMsg), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AuthSigMessage { + #[prost(message, optional, tag = "1")] + pub pub_key: ::core::option::Option, + #[prost(bytes = "vec", tag = "2")] + pub sig: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NetAddress { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub ip: ::prost::alloc::string::String, + #[prost(uint32, tag = "3")] + pub port: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtocolVersion { + #[prost(uint64, tag = "1")] + pub p2p: u64, + #[prost(uint64, tag = "2")] + pub block: u64, + #[prost(uint64, tag = "3")] + pub app: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DefaultNodeInfo { + #[prost(message, optional, tag = "1")] + pub protocol_version: ::core::option::Option, + #[prost(string, tag = "2")] + pub default_node_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub listen_addr: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub network: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub version: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "6")] + pub channels: ::prost::alloc::vec::Vec, + #[prost(string, tag = "7")] + pub moniker: ::prost::alloc::string::String, + #[prost(message, optional, tag = "8")] + pub other: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DefaultNodeInfoOther { + #[prost(string, tag = "1")] + pub tx_index: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub rpc_address: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PexRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PexAddrs { + #[prost(message, repeated, tag = "1")] + pub addrs: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + #[prost(oneof = "message::Sum", tags = "1, 2")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + PexRequest(super::PexRequest), + #[prost(message, tag = "2")] + PexAddrs(super::PexAddrs), + } +} diff --git a/proto/src/prost/v0_37/tendermint.privval.rs b/proto/src/prost/v0_37/tendermint.privval.rs new file mode 100644 index 000000000..1fae1cbee --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.privval.rs @@ -0,0 +1,123 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoteSignerError { + #[prost(int32, tag = "1")] + pub code: i32, + #[prost(string, tag = "2")] + pub description: ::prost::alloc::string::String, +} +/// PubKeyRequest requests the consensus public key from the remote signer. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PubKeyRequest { + #[prost(string, tag = "1")] + pub chain_id: ::prost::alloc::string::String, +} +/// PubKeyResponse is a response message containing the public key. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PubKeyResponse { + #[prost(message, optional, tag = "1")] + pub pub_key: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub error: ::core::option::Option, +} +/// SignVoteRequest is a request to sign a vote +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignVoteRequest { + #[prost(message, optional, tag = "1")] + pub vote: ::core::option::Option, + #[prost(string, tag = "2")] + pub chain_id: ::prost::alloc::string::String, +} +/// SignedVoteResponse is a response containing a signed vote or an error +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignedVoteResponse { + #[prost(message, optional, tag = "1")] + pub vote: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub error: ::core::option::Option, +} +/// SignProposalRequest is a request to sign a proposal +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignProposalRequest { + #[prost(message, optional, tag = "1")] + pub proposal: ::core::option::Option, + #[prost(string, tag = "2")] + pub chain_id: ::prost::alloc::string::String, +} +/// SignedProposalResponse is response containing a signed proposal or an error +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignedProposalResponse { + #[prost(message, optional, tag = "1")] + pub proposal: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub error: ::core::option::Option, +} +/// PingRequest is a request to confirm that the connection is alive. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PingRequest {} +/// PingResponse is a response to confirm that the connection is alive. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PingResponse {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + #[prost(oneof = "message::Sum", tags = "1, 2, 3, 4, 5, 6, 7, 8")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + PubKeyRequest(super::PubKeyRequest), + #[prost(message, tag = "2")] + PubKeyResponse(super::PubKeyResponse), + #[prost(message, tag = "3")] + SignVoteRequest(super::SignVoteRequest), + #[prost(message, tag = "4")] + SignedVoteResponse(super::SignedVoteResponse), + #[prost(message, tag = "5")] + SignProposalRequest(super::SignProposalRequest), + #[prost(message, tag = "6")] + SignedProposalResponse(super::SignedProposalResponse), + #[prost(message, tag = "7")] + PingRequest(super::PingRequest), + #[prost(message, tag = "8")] + PingResponse(super::PingResponse), + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum Errors { + Unknown = 0, + UnexpectedResponse = 1, + NoConnection = 2, + ConnectionTimeout = 3, + ReadTimeout = 4, + WriteTimeout = 5, +} +impl Errors { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Errors::Unknown => "ERRORS_UNKNOWN", + Errors::UnexpectedResponse => "ERRORS_UNEXPECTED_RESPONSE", + Errors::NoConnection => "ERRORS_NO_CONNECTION", + Errors::ConnectionTimeout => "ERRORS_CONNECTION_TIMEOUT", + Errors::ReadTimeout => "ERRORS_READ_TIMEOUT", + Errors::WriteTimeout => "ERRORS_WRITE_TIMEOUT", + } + } +} diff --git a/proto/src/prost/v0_37/tendermint.rpc.grpc.rs b/proto/src/prost/v0_37/tendermint.rpc.grpc.rs new file mode 100644 index 000000000..5630cb50c --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.rpc.grpc.rs @@ -0,0 +1,20 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestPing {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestBroadcastTx { + #[prost(bytes = "vec", tag = "1")] + pub tx: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponsePing {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResponseBroadcastTx { + #[prost(message, optional, tag = "1")] + pub check_tx: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub deliver_tx: ::core::option::Option, +} diff --git a/proto/src/prost/v0_37/tendermint.state.rs b/proto/src/prost/v0_37/tendermint.state.rs new file mode 100644 index 000000000..dd006a2c6 --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.state.rs @@ -0,0 +1,91 @@ +/// ABCIResponses retains the responses +/// of the various ABCI calls during block processing. +/// It is persisted to disk for each height before calling Commit. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AbciResponses { + #[prost(message, repeated, tag = "1")] + pub deliver_txs: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub end_block: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub begin_block: ::core::option::Option, +} +/// ValidatorsInfo represents the latest validator set, or the last height it changed +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValidatorsInfo { + #[prost(message, optional, tag = "1")] + pub validator_set: ::core::option::Option, + #[prost(int64, tag = "2")] + pub last_height_changed: i64, +} +/// ConsensusParamsInfo represents the latest consensus params, or the last height it changed +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConsensusParamsInfo { + #[prost(message, optional, tag = "1")] + pub consensus_params: ::core::option::Option, + #[prost(int64, tag = "2")] + pub last_height_changed: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AbciResponsesInfo { + #[prost(message, optional, tag = "1")] + pub abci_responses: ::core::option::Option, + #[prost(int64, tag = "2")] + pub height: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Version { + #[prost(message, optional, tag = "1")] + pub consensus: ::core::option::Option, + #[prost(string, tag = "2")] + pub software: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct State { + #[prost(message, optional, tag = "1")] + pub version: ::core::option::Option, + /// immutable + #[prost(string, tag = "2")] + pub chain_id: ::prost::alloc::string::String, + #[prost(int64, tag = "14")] + pub initial_height: i64, + /// LastBlockHeight=0 at genesis (ie. block(H=0) does not exist) + #[prost(int64, tag = "3")] + pub last_block_height: i64, + #[prost(message, optional, tag = "4")] + pub last_block_id: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub last_block_time: ::core::option::Option, + /// LastValidators is used to validate block.LastCommit. + /// Validators are persisted to the database separately every time they change, + /// so we can query for historical validator sets. + /// Note that if s.LastBlockHeight causes a valset change, + /// we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1 + 1 + /// Extra +1 due to nextValSet delay. + #[prost(message, optional, tag = "6")] + pub next_validators: ::core::option::Option, + #[prost(message, optional, tag = "7")] + pub validators: ::core::option::Option, + #[prost(message, optional, tag = "8")] + pub last_validators: ::core::option::Option, + #[prost(int64, tag = "9")] + pub last_height_validators_changed: i64, + /// Consensus parameters used for validating blocks. + /// Changes returned by EndBlock and updated after Commit. + #[prost(message, optional, tag = "10")] + pub consensus_params: ::core::option::Option, + #[prost(int64, tag = "11")] + pub last_height_consensus_params_changed: i64, + /// Merkle root of the results from executing prev block + #[prost(bytes = "vec", tag = "12")] + pub last_results_hash: ::prost::alloc::vec::Vec, + /// the latest AppHash we've received from calling abci.Commit() + #[prost(bytes = "vec", tag = "13")] + pub app_hash: ::prost::alloc::vec::Vec, +} diff --git a/proto/src/prost/v0_37/tendermint.statesync.rs b/proto/src/prost/v0_37/tendermint.statesync.rs new file mode 100644 index 000000000..a2ad034e3 --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.statesync.rs @@ -0,0 +1,62 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + #[prost(oneof = "message::Sum", tags = "1, 2, 3, 4")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + SnapshotsRequest(super::SnapshotsRequest), + #[prost(message, tag = "2")] + SnapshotsResponse(super::SnapshotsResponse), + #[prost(message, tag = "3")] + ChunkRequest(super::ChunkRequest), + #[prost(message, tag = "4")] + ChunkResponse(super::ChunkResponse), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotsRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotsResponse { + #[prost(uint64, tag = "1")] + pub height: u64, + #[prost(uint32, tag = "2")] + pub format: u32, + #[prost(uint32, tag = "3")] + pub chunks: u32, + #[prost(bytes = "vec", tag = "4")] + pub hash: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "5")] + pub metadata: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ChunkRequest { + #[prost(uint64, tag = "1")] + pub height: u64, + #[prost(uint32, tag = "2")] + pub format: u32, + #[prost(uint32, tag = "3")] + pub index: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ChunkResponse { + #[prost(uint64, tag = "1")] + pub height: u64, + #[prost(uint32, tag = "2")] + pub format: u32, + #[prost(uint32, tag = "3")] + pub index: u32, + #[prost(bytes = "vec", tag = "4")] + pub chunk: ::prost::alloc::vec::Vec, + #[prost(bool, tag = "5")] + pub missing: bool, +} diff --git a/proto/src/prost/v0_37/tendermint.store.rs b/proto/src/prost/v0_37/tendermint.store.rs new file mode 100644 index 000000000..98d20b0fc --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.store.rs @@ -0,0 +1,8 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockStoreState { + #[prost(int64, tag = "1")] + pub base: i64, + #[prost(int64, tag = "2")] + pub height: i64, +} diff --git a/proto/src/prost/v0_37/tendermint.types.rs b/proto/src/prost/v0_37/tendermint.types.rs new file mode 100644 index 000000000..3b93c0932 --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.types.rs @@ -0,0 +1,543 @@ +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValidatorSet { + #[prost(message, repeated, tag = "1")] + pub validators: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub proposer: ::core::option::Option, + #[prost(int64, tag = "3")] + pub total_voting_power: i64, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Validator { + #[prost(bytes = "vec", tag = "1")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub address: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub pub_key: ::core::option::Option, + #[prost(int64, tag = "3")] + #[serde(alias = "power", with = "crate::serializers::from_str")] + pub voting_power: i64, + #[prost(int64, tag = "4")] + #[serde(with = "crate::serializers::from_str", default)] + pub proposer_priority: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SimpleValidator { + #[prost(message, optional, tag = "1")] + pub pub_key: ::core::option::Option, + #[prost(int64, tag = "2")] + pub voting_power: i64, +} +/// PartsetHeader +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PartSetHeader { + #[prost(uint32, tag = "1")] + #[serde(with = "crate::serializers::part_set_header_total")] + pub total: u32, + #[prost(bytes = "vec", tag = "2")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub hash: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Part { + #[prost(uint32, tag = "1")] + pub index: u32, + #[prost(bytes = "vec", tag = "2")] + pub bytes: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "3")] + pub proof: ::core::option::Option, +} +/// BlockID +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockId { + #[prost(bytes = "vec", tag = "1")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub hash: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + #[serde(alias = "parts")] + pub part_set_header: ::core::option::Option, +} +/// Header defines the structure of a Tendermint block header. +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Header { + /// basic block info + #[prost(message, optional, tag = "1")] + pub version: ::core::option::Option, + #[prost(string, tag = "2")] + pub chain_id: ::prost::alloc::string::String, + #[prost(int64, tag = "3")] + #[serde(with = "crate::serializers::from_str")] + pub height: i64, + #[prost(message, optional, tag = "4")] + #[serde(with = "crate::serializers::optional")] + pub time: ::core::option::Option, + /// prev block info + #[prost(message, optional, tag = "5")] + pub last_block_id: ::core::option::Option, + /// hashes of block data + /// + /// commit from validators from the last block + #[prost(bytes = "vec", tag = "6")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub last_commit_hash: ::prost::alloc::vec::Vec, + /// transactions + #[prost(bytes = "vec", tag = "7")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub data_hash: ::prost::alloc::vec::Vec, + /// hashes from the app output from the prev block + /// + /// validators for the current block + #[prost(bytes = "vec", tag = "8")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub validators_hash: ::prost::alloc::vec::Vec, + /// validators for the next block + #[prost(bytes = "vec", tag = "9")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub next_validators_hash: ::prost::alloc::vec::Vec, + /// consensus params for current block + #[prost(bytes = "vec", tag = "10")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub consensus_hash: ::prost::alloc::vec::Vec, + /// state after txs from the previous block + #[prost(bytes = "vec", tag = "11")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub app_hash: ::prost::alloc::vec::Vec, + /// root hash of all results from the txs from the previous block + #[prost(bytes = "vec", tag = "12")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub last_results_hash: ::prost::alloc::vec::Vec, + /// consensus info + /// + /// evidence included in the block + #[prost(bytes = "vec", tag = "13")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub evidence_hash: ::prost::alloc::vec::Vec, + /// original proposer of the block + #[prost(bytes = "vec", tag = "14")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub proposer_address: ::prost::alloc::vec::Vec, +} +/// Data contains the set of transactions included in the block +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Data { + /// Txs that will be applied by state @ block.Height+1. + /// NOTE: not all txs here are valid. We're just agreeing on the order first. + /// This means that block.AppHash does not include these txs. + #[prost(bytes = "vec", repeated, tag = "1")] + #[serde(with = "crate::serializers::txs")] + pub txs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +/// Vote represents a prevote, precommit, or commit vote from validators for +/// consensus. +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Vote { + #[prost(enumeration = "SignedMsgType", tag = "1")] + pub r#type: i32, + #[prost(int64, tag = "2")] + #[serde(with = "crate::serializers::from_str")] + pub height: i64, + #[prost(int32, tag = "3")] + pub round: i32, + /// zero if vote is nil. + #[prost(message, optional, tag = "4")] + pub block_id: ::core::option::Option, + #[prost(message, optional, tag = "5")] + #[serde(with = "crate::serializers::optional")] + pub timestamp: ::core::option::Option, + #[prost(bytes = "vec", tag = "6")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub validator_address: ::prost::alloc::vec::Vec, + #[prost(int32, tag = "7")] + pub validator_index: i32, + #[prost(bytes = "vec", tag = "8")] + #[serde(with = "crate::serializers::bytes::base64string")] + pub signature: ::prost::alloc::vec::Vec, +} +/// Commit contains the evidence that a block was committed by a set of validators. +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Commit { + #[prost(int64, tag = "1")] + #[serde(with = "crate::serializers::from_str")] + pub height: i64, + #[prost(int32, tag = "2")] + pub round: i32, + #[prost(message, optional, tag = "3")] + pub block_id: ::core::option::Option, + #[prost(message, repeated, tag = "4")] + #[serde(with = "crate::serializers::nullable")] + pub signatures: ::prost::alloc::vec::Vec, +} +/// CommitSig is a part of the Vote included in a Commit. +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitSig { + #[prost(enumeration = "BlockIdFlag", tag = "1")] + pub block_id_flag: i32, + #[prost(bytes = "vec", tag = "2")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub validator_address: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "3")] + #[serde(with = "crate::serializers::optional")] + pub timestamp: ::core::option::Option, + #[prost(bytes = "vec", tag = "4")] + #[serde(with = "crate::serializers::bytes::base64string")] + pub signature: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Proposal { + #[prost(enumeration = "SignedMsgType", tag = "1")] + pub r#type: i32, + #[prost(int64, tag = "2")] + pub height: i64, + #[prost(int32, tag = "3")] + pub round: i32, + #[prost(int32, tag = "4")] + pub pol_round: i32, + #[prost(message, optional, tag = "5")] + pub block_id: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub timestamp: ::core::option::Option, + #[prost(bytes = "vec", tag = "7")] + pub signature: ::prost::alloc::vec::Vec, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignedHeader { + #[prost(message, optional, tag = "1")] + pub header: ::core::option::Option
, + #[prost(message, optional, tag = "2")] + pub commit: ::core::option::Option, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LightBlock { + #[prost(message, optional, tag = "1")] + pub signed_header: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub validator_set: ::core::option::Option, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockMeta { + #[prost(message, optional, tag = "1")] + pub block_id: ::core::option::Option, + #[prost(int64, tag = "2")] + #[serde(with = "crate::serializers::from_str")] + pub block_size: i64, + #[prost(message, optional, tag = "3")] + pub header: ::core::option::Option
, + #[prost(int64, tag = "4")] + #[serde(with = "crate::serializers::from_str")] + pub num_txs: i64, +} +/// TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TxProof { + #[prost(bytes = "vec", tag = "1")] + #[serde(with = "crate::serializers::bytes::hexstring")] + pub root_hash: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "2")] + #[serde(with = "crate::serializers::bytes::base64string")] + pub data: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "3")] + pub proof: ::core::option::Option, +} +/// BlockIdFlag indicates which BlcokID the signature is for +#[derive(::num_derive::FromPrimitive, ::num_derive::ToPrimitive)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum BlockIdFlag { + Unknown = 0, + Absent = 1, + Commit = 2, + Nil = 3, +} +impl BlockIdFlag { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + BlockIdFlag::Unknown => "BLOCK_ID_FLAG_UNKNOWN", + BlockIdFlag::Absent => "BLOCK_ID_FLAG_ABSENT", + BlockIdFlag::Commit => "BLOCK_ID_FLAG_COMMIT", + BlockIdFlag::Nil => "BLOCK_ID_FLAG_NIL", + } + } +} +/// SignedMsgType is a type of signed message in the consensus. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum SignedMsgType { + Unknown = 0, + /// Votes + Prevote = 1, + Precommit = 2, + /// Proposals + Proposal = 32, +} +impl SignedMsgType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + SignedMsgType::Unknown => "SIGNED_MSG_TYPE_UNKNOWN", + SignedMsgType::Prevote => "SIGNED_MSG_TYPE_PREVOTE", + SignedMsgType::Precommit => "SIGNED_MSG_TYPE_PRECOMMIT", + SignedMsgType::Proposal => "SIGNED_MSG_TYPE_PROPOSAL", + } + } +} +/// ConsensusParams contains consensus critical parameters that determine the +/// validity of blocks. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConsensusParams { + #[prost(message, optional, tag = "1")] + pub block: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub evidence: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub validator: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub version: ::core::option::Option, +} +/// BlockParams contains limits on the block size. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockParams { + /// Max block size, in bytes. + /// Note: must be greater than 0 + #[prost(int64, tag = "1")] + pub max_bytes: i64, + /// Max gas per block. + /// Note: must be greater or equal to -1 + #[prost(int64, tag = "2")] + pub max_gas: i64, +} +/// EvidenceParams determine how we handle evidence of malfeasance. +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EvidenceParams { + /// Max age of evidence, in blocks. + /// + /// The basic formula for calculating this is: MaxAgeDuration / {average block + /// time}. + #[prost(int64, tag = "1")] + pub max_age_num_blocks: i64, + /// Max age of evidence, in time. + /// + /// It should correspond with an app's "unbonding period" or other similar + /// mechanism for handling [Nothing-At-Stake + /// attacks](). + #[prost(message, optional, tag = "2")] + pub max_age_duration: ::core::option::Option, + /// This sets the maximum size of total evidence in bytes that can be committed in a single block. + /// and should fall comfortably under the max block bytes. + /// Default is 1048576 or 1MB + #[prost(int64, tag = "3")] + #[serde(with = "crate::serializers::from_str", default)] + pub max_bytes: i64, +} +/// ValidatorParams restrict the public key types validators can use. +/// NOTE: uses ABCI pubkey naming, not Amino names. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValidatorParams { + #[prost(string, repeated, tag = "1")] + pub pub_key_types: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +/// VersionParams contains the ABCI application version. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VersionParams { + #[prost(uint64, tag = "1")] + pub app: u64, +} +/// HashedParams is a subset of ConsensusParams. +/// +/// It is hashed into the Header.ConsensusHash. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HashedParams { + #[prost(int64, tag = "1")] + pub block_max_bytes: i64, + #[prost(int64, tag = "2")] + pub block_max_gas: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EventDataRoundState { + #[prost(int64, tag = "1")] + pub height: i64, + #[prost(int32, tag = "2")] + pub round: i32, + #[prost(string, tag = "3")] + pub step: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Evidence { + #[prost(oneof = "evidence::Sum", tags = "1, 2")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `Evidence`. +pub mod evidence { + #[derive(::serde::Deserialize, ::serde::Serialize)] + #[serde(tag = "type", content = "value")] + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag = "1")] + #[serde(rename = "tendermint/DuplicateVoteEvidence")] + DuplicateVoteEvidence(super::DuplicateVoteEvidence), + #[prost(message, tag = "2")] + #[serde(rename = "tendermint/LightClientAttackEvidence")] + LightClientAttackEvidence(super::LightClientAttackEvidence), + } +} +/// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes. +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DuplicateVoteEvidence { + #[prost(message, optional, tag = "1")] + pub vote_a: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub vote_b: ::core::option::Option, + #[prost(int64, tag = "3")] + #[serde(alias = "TotalVotingPower", with = "crate::serializers::from_str")] + pub total_voting_power: i64, + #[prost(int64, tag = "4")] + #[serde(alias = "ValidatorPower", with = "crate::serializers::from_str")] + pub validator_power: i64, + #[prost(message, optional, tag = "5")] + #[serde(alias = "Timestamp")] + pub timestamp: ::core::option::Option, +} +/// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client. +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LightClientAttackEvidence { + #[prost(message, optional, tag = "1")] + pub conflicting_block: ::core::option::Option, + #[prost(int64, tag = "2")] + pub common_height: i64, + #[prost(message, repeated, tag = "3")] + pub byzantine_validators: ::prost::alloc::vec::Vec, + #[prost(int64, tag = "4")] + pub total_voting_power: i64, + #[prost(message, optional, tag = "5")] + pub timestamp: ::core::option::Option, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EvidenceList { + #[prost(message, repeated, tag = "1")] + #[serde(with = "crate::serializers::nullable")] + pub evidence: ::prost::alloc::vec::Vec, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Block { + #[prost(message, optional, tag = "1")] + pub header: ::core::option::Option
, + #[prost(message, optional, tag = "2")] + pub data: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub evidence: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub last_commit: ::core::option::Option, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CanonicalBlockId { + #[prost(bytes = "vec", tag = "1")] + pub hash: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + #[serde(alias = "parts")] + pub part_set_header: ::core::option::Option, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CanonicalPartSetHeader { + #[prost(uint32, tag = "1")] + pub total: u32, + #[prost(bytes = "vec", tag = "2")] + pub hash: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CanonicalProposal { + /// type alias for byte + #[prost(enumeration = "SignedMsgType", tag = "1")] + pub r#type: i32, + /// canonicalization requires fixed size encoding here + #[prost(sfixed64, tag = "2")] + pub height: i64, + /// canonicalization requires fixed size encoding here + #[prost(sfixed64, tag = "3")] + pub round: i64, + #[prost(int64, tag = "4")] + pub pol_round: i64, + #[prost(message, optional, tag = "5")] + pub block_id: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub timestamp: ::core::option::Option, + #[prost(string, tag = "7")] + pub chain_id: ::prost::alloc::string::String, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CanonicalVote { + /// type alias for byte + #[prost(enumeration = "SignedMsgType", tag = "1")] + pub r#type: i32, + /// canonicalization requires fixed size encoding here + #[prost(sfixed64, tag = "2")] + pub height: i64, + /// canonicalization requires fixed size encoding here + #[prost(sfixed64, tag = "3")] + pub round: i64, + #[prost(message, optional, tag = "4")] + pub block_id: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub timestamp: ::core::option::Option, + #[prost(string, tag = "6")] + pub chain_id: ::prost::alloc::string::String, +} diff --git a/proto/src/prost/v0_37/tendermint.version.rs b/proto/src/prost/v0_37/tendermint.version.rs new file mode 100644 index 000000000..8a77a26fc --- /dev/null +++ b/proto/src/prost/v0_37/tendermint.version.rs @@ -0,0 +1,25 @@ +/// App includes the protocol and software version for the application. +/// This information is included in ResponseInfo. The App.Protocol can be +/// updated in ResponseEndBlock. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct App { + #[prost(uint64, tag = "1")] + pub protocol: u64, + #[prost(string, tag = "2")] + pub software: ::prost::alloc::string::String, +} +/// Consensus captures the consensus rules for processing a block in the blockchain, +/// including all blockchain data structures and the rules of the application's +/// state transition machine. +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Consensus { + #[prost(uint64, tag = "1")] + #[serde(with = "crate::serializers::from_str")] + pub block: u64, + #[prost(uint64, tag = "2")] + #[serde(with = "crate::serializers::from_str", default)] + pub app: u64, +} diff --git a/proto/src/serializers.rs b/proto/src/serializers.rs index 651a197f6..161833816 100644 --- a/proto/src/serializers.rs +++ b/proto/src/serializers.rs @@ -52,8 +52,10 @@ // Todo: remove dead_code allowance as soon as more types are implemented #![allow(dead_code)] + +pub mod allow_null; pub mod bytes; -pub mod evidence; +mod evidence; pub mod from_str; pub mod nullable; pub mod optional; diff --git a/proto/src/serializers/allow_null.rs b/proto/src/serializers/allow_null.rs new file mode 100644 index 000000000..b9c9bf463 --- /dev/null +++ b/proto/src/serializers/allow_null.rs @@ -0,0 +1,27 @@ +//! Serialize/deserialize `nil`able value into `T`, where `nil` turns into the `Default` value. +//! +//! Serialize any value of `T`, including the default value, +//! using the serialization for `Some` variant of `Option`. +//! +//! This helper can be used to tolerate `nil` values from a serialization producer, +//! while the default value is normatively serialized as such. + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// Deserialize `T` from a `nil`-able representation, accepting the `nil` +pub fn deserialize<'de, D, T>(deserializer: D) -> Result +where + D: Deserializer<'de>, + T: Deserialize<'de> + Default, +{ + Ok(Option::::deserialize(deserializer)?.unwrap_or_default()) +} + +/// Serialize `T` as `Some` value of `Option`. +pub fn serialize(value: &T, serializer: S) -> Result +where + S: Serializer, + T: Serialize, +{ + serializer.serialize_some(value) +} diff --git a/proto/src/serializers/evidence.rs b/proto/src/serializers/evidence.rs index fdfffdeef..7136455c5 100644 --- a/proto/src/serializers/evidence.rs +++ b/proto/src/serializers/evidence.rs @@ -1,73 +1,47 @@ -use crate::tendermint::types::{evidence::Sum, Evidence}; +mod v0_34 { + use crate::v0_34::types::{evidence, Evidence}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; -/// EvidenceVariant helper struct for evidence serialization -/// This is a workaround until we figure a better way of JSON serializing evidence. -/// It is a modified copy of the crate::tendermint::types::evidence::Sum struct. -#[allow(clippy::large_enum_variant)] -#[derive(Clone, PartialEq, ::serde::Deserialize, ::serde::Serialize)] -#[serde(tag = "type", content = "value")] -pub enum EvidenceVariant { - /// Provided for when the evidence struct's optional `sum` field is `None`. - None, - #[serde(rename = "tendermint/DuplicateVoteEvidence")] - DuplicateVoteEvidence(crate::tendermint::types::DuplicateVoteEvidence), - #[serde(rename = "tendermint/LightClientAttackEvidence")] - LightClientAttackEvidence(crate::tendermint::types::LightClientAttackEvidence), -} - -impl From for Evidence { - fn from(value: EvidenceVariant) -> Self { - match value { - EvidenceVariant::None => Evidence { sum: None }, - _ => Evidence { - sum: Some(value.into()), - }, + impl<'de> Deserialize<'de> for Evidence { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let sum = Option::::deserialize(deserializer)?; + Ok(Self { sum }) } } -} -impl From for EvidenceVariant { - fn from(value: Evidence) -> Self { - match value.sum { - Some(sum) => sum.into(), - None => Self::None, + impl Serialize for Evidence { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.sum.serialize(serializer) } } } -impl From for EvidenceVariant { - fn from(value: Sum) -> Self { - match value { - Sum::DuplicateVoteEvidence(d) => Self::DuplicateVoteEvidence(d), - Sum::LightClientAttackEvidence(l) => Self::LightClientAttackEvidence(l), - } - } -} +mod v0_37 { + use crate::v0_37::types::{evidence, Evidence}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; -impl From for Sum { - fn from(value: EvidenceVariant) -> Self { - match value { - // This should never be called - should be handled instead in the - // `impl From for Evidence` above. - EvidenceVariant::None => { - panic!("non-existent evidence cannot be converted into its protobuf representation") - }, - EvidenceVariant::DuplicateVoteEvidence(d) => Self::DuplicateVoteEvidence(d), - EvidenceVariant::LightClientAttackEvidence(l) => Self::LightClientAttackEvidence(l), + impl<'de> Deserialize<'de> for Evidence { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let sum = Option::::deserialize(deserializer)?; + Ok(Self { sum }) } } -} -#[cfg(test)] -mod test { - use super::*; - - // Minimally reproduce https://github.com/informalsystems/tendermint-rs/issues/782 - #[test] - fn empty_evidence() { - let ev = Evidence { sum: None }; - let ev_json = serde_json::to_string(&ev).unwrap(); - let ev_deserialized = serde_json::from_str::(&ev_json).unwrap(); - assert_eq!(ev, ev_deserialized); + impl Serialize for Evidence { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.sum.serialize(serializer) + } } } diff --git a/proto/src/tendermint.rs b/proto/src/tendermint.rs index e4d9b7e46..4a8211a91 100644 --- a/proto/src/tendermint.rs +++ b/proto/src/tendermint.rs @@ -1,66 +1,3 @@ -//! Tendermint-proto auto-generated sub-modules for Tendermint - -pub mod statesync { - include!("prost/tendermint.statesync.rs"); -} - -pub mod abci { - include!("prost/tendermint.abci.rs"); -} - -pub mod store { - include!("prost/tendermint.store.rs"); -} - -pub mod version { - include!("prost/tendermint.version.rs"); -} - -pub mod types { - include!("prost/tendermint.types.rs"); -} - -pub mod consensus { - include!("prost/tendermint.consensus.rs"); -} - -pub mod p2p { - include!("prost/tendermint.p2p.rs"); -} - -pub mod privval { - include!("prost/tendermint.privval.rs"); -} - -pub mod blockchain { - include!("prost/tendermint.blockchain.rs"); -} - -pub mod crypto { - include!("prost/tendermint.crypto.rs"); -} - -pub mod mempool { - include!("prost/tendermint.mempool.rs"); -} - -pub mod state { - include!("prost/tendermint.state.rs"); -} - -pub mod libs { - pub mod bits { - include!("prost/tendermint.libs.bits.rs"); - } -} - -pub mod rpc { - pub mod grpc { - include!("prost/tendermint.rpc.grpc.rs"); - } -} - -pub mod meta { - pub const REPOSITORY: &str = "https://github.com/tendermint/tendermint"; - pub const COMMITISH: &str = "v0.34.21"; -} +pub mod v0_34; +pub mod v0_37; +pub use v0_37::*; diff --git a/proto/src/tendermint/v0_34.rs b/proto/src/tendermint/v0_34.rs new file mode 100644 index 000000000..2457ed879 --- /dev/null +++ b/proto/src/tendermint/v0_34.rs @@ -0,0 +1,66 @@ +//! Tendermint-proto auto-generated sub-modules for Tendermint + +pub mod abci { + include!("../prost/v0_34/tendermint.abci.rs"); +} + +pub mod blockchain { + include!("../prost/v0_34/tendermint.blockchain.rs"); +} + +pub mod consensus { + include!("../prost/v0_34/tendermint.consensus.rs"); +} + +pub mod crypto { + include!("../prost/v0_34/tendermint.crypto.rs"); +} + +pub mod libs { + pub mod bits { + include!("../prost/v0_34/tendermint.libs.bits.rs"); + } +} + +pub mod mempool { + include!("../prost/v0_34/tendermint.mempool.rs"); +} + +pub mod p2p { + include!("../prost/v0_34/tendermint.p2p.rs"); +} + +pub mod privval { + include!("../prost/v0_34/tendermint.privval.rs"); +} + +pub mod rpc { + pub mod grpc { + include!("../prost/v0_34/tendermint.rpc.grpc.rs"); + } +} + +pub mod state { + include!("../prost/v0_34/tendermint.state.rs"); +} + +pub mod statesync { + include!("../prost/v0_34/tendermint.statesync.rs"); +} + +pub mod store { + include!("../prost/v0_34/tendermint.store.rs"); +} + +pub mod types { + include!("../prost/v0_34/tendermint.types.rs"); +} + +pub mod version { + include!("../prost/v0_34/tendermint.version.rs"); +} + +pub mod meta { + pub const REPOSITORY: &str = "https://github.com/tendermint/tendermint"; + pub const COMMITISH: &str = "v0.34.24"; +} diff --git a/proto/src/tendermint/v0_37.rs b/proto/src/tendermint/v0_37.rs new file mode 100644 index 000000000..292f1a337 --- /dev/null +++ b/proto/src/tendermint/v0_37.rs @@ -0,0 +1,66 @@ +//! Tendermint-proto auto-generated sub-modules for Tendermint + +pub mod abci { + include!("../prost/v0_37/tendermint.abci.rs"); +} + +pub mod blocksync { + include!("../prost/v0_37/tendermint.blocksync.rs"); +} + +pub mod consensus { + include!("../prost/v0_37/tendermint.consensus.rs"); +} + +pub mod crypto { + include!("../prost/v0_37/tendermint.crypto.rs"); +} + +pub mod libs { + pub mod bits { + include!("../prost/v0_37/tendermint.libs.bits.rs"); + } +} + +pub mod mempool { + include!("../prost/v0_37/tendermint.mempool.rs"); +} + +pub mod p2p { + include!("../prost/v0_37/tendermint.p2p.rs"); +} + +pub mod privval { + include!("../prost/v0_37/tendermint.privval.rs"); +} + +pub mod rpc { + pub mod grpc { + include!("../prost/v0_37/tendermint.rpc.grpc.rs"); + } +} + +pub mod state { + include!("../prost/v0_37/tendermint.state.rs"); +} + +pub mod statesync { + include!("../prost/v0_37/tendermint.statesync.rs"); +} + +pub mod store { + include!("../prost/v0_37/tendermint.store.rs"); +} + +pub mod types { + include!("../prost/v0_37/tendermint.types.rs"); +} + +pub mod version { + include!("../prost/v0_37/tendermint.version.rs"); +} + +pub mod meta { + pub const REPOSITORY: &str = "https://github.com/tendermint/tendermint"; + pub const COMMITISH: &str = "v0.37.0-alpha.1"; +} diff --git a/proto/tests/unit.rs b/proto/tests/unit.rs index 1aa161c8e..d0bc59d4d 100644 --- a/proto/tests/unit.rs +++ b/proto/tests/unit.rs @@ -1,9 +1,7 @@ use core::convert::TryFrom; -use tendermint_proto::{ - types::{BlockId as RawBlockId, PartSetHeader as RawPartSetHeader}, - Protobuf, -}; +use tendermint_proto::v0_37::types::{BlockId as RawBlockId, PartSetHeader as RawPartSetHeader}; +use tendermint_proto::Protobuf; impl Protobuf for BlockId {} diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 65e4033f1..02e2abcaf 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -43,6 +43,7 @@ http-client = [ "hyper", "hyper-proxy", "hyper-rustls", + "semver", "tokio/fs", "tokio/macros", "tracing" @@ -53,6 +54,7 @@ websocket-client = [ "async-tungstenite", "futures", "http", + "semver", "tokio/rt-multi-thread", "tokio/fs", "tokio/macros", @@ -88,6 +90,7 @@ http = { version = "0.2", optional = true, default-features = false } hyper = { version = "0.14", optional = true, default-features = false, features = ["client", "http1", "http2"] } hyper-proxy = { version = "0.9.1", optional = true, default-features = false, features = ["rustls"] } hyper-rustls = { version = "0.22.1", optional = true, default-features = false, features = ["rustls-native-certs", "webpki-roots", "tokio-runtime"] } +semver = { version = "1.0", optional = true, default-features = false } structopt = { version = "0.3", optional = true, default-features = false } tokio = { version = "1.0", optional = true, default-features = false, features = ["rt-multi-thread"] } tracing = { version = "0.1", optional = true, default-features = false } diff --git a/rpc/src/client.rs b/rpc/src/client.rs index 403baa5a4..9194b190d 100644 --- a/rpc/src/client.rs +++ b/rpc/src/client.rs @@ -1,16 +1,13 @@ //! Tendermint RPC client. +mod compat; +pub use compat::CompatMode; mod subscription; pub use subscription::{Subscription, SubscriptionClient}; pub mod sync; mod transport; -use core::{fmt, time::Duration}; -use async_trait::async_trait; -use serde::{de::DeserializeOwned, Serialize}; -use tendermint::{abci, block::Height, evidence::Evidence, Genesis, Hash}; -use tokio::time; #[cfg(feature = "http-client")] pub use transport::http::{HttpClient, HttpClientUrl}; pub use transport::mock::{MockClient, MockRequestMatcher, MockRequestMethodMatcher}; @@ -19,6 +16,13 @@ pub use transport::websocket::{ WebSocketClient, WebSocketClientDriver, WebSocketClientUrl, WebSocketConfig, }; +use core::{fmt, time::Duration}; + +use async_trait::async_trait; +use serde::{de::DeserializeOwned, Serialize}; +use tendermint::{abci, block::Height, evidence::Evidence, Genesis, Hash}; +use tokio::time; + use crate::{ endpoint::{validators::DEFAULT_VALIDATORS_PER_PAGE, *}, paging::Paging, @@ -79,6 +83,22 @@ pub trait Client { self.perform(block::Request::default()).await } + /// `/header`: get block header at a given height. + async fn header(&self, height: H) -> Result + where + H: Into + Send, + { + self.perform(header::Request::new(height.into())).await + } + + /// `/header_by_hash`: get block by hash. + async fn header_by_hash( + &self, + hash: tendermint::Hash, + ) -> Result { + self.perform(header_by_hash::Request::new(hash)).await + } + /// `/block_results`: get ABCI results for a block at a particular height. async fn block_results(&self, height: H) -> Result where @@ -299,8 +319,11 @@ pub trait Client { Ok(()) } - /// Perform a request against the RPC endpoint - async fn perform(&self, request: R) -> Result + /// Perform a request against the RPC endpoint. + /// + /// This method is used by the default implementations of specific + /// endpoint methods. The latest protocol dialect is assumed to be invoked. + async fn perform(&self, request: R) -> Result where R: SimpleRequest; } diff --git a/rpc/src/client/bin/main.rs b/rpc/src/client/bin/main.rs index 46816f25a..7e2bb578e 100644 --- a/rpc/src/client/bin/main.rs +++ b/rpc/src/client/bin/main.rs @@ -6,11 +6,15 @@ use futures::StreamExt; use structopt::StructOpt; use tendermint::Hash; use tendermint_rpc::{ - query::Query, Client, Error, HttpClient, Order, Paging, Scheme, Subscription, - SubscriptionClient, Url, WebSocketClient, + client::CompatMode, + dialect::{Dialect, LatestDialect}, + event::DialectEvent, + query::Query, + Client, Error, HttpClient, Order, Paging, Scheme, Subscription, SubscriptionClient, Url, + WebSocketClient, }; -use tokio::time::Duration; -use tracing::{error, info, level_filters::LevelFilter, warn}; +use tokio::{task::JoinHandle, time::Duration}; +use tracing::{debug, error, info, level_filters::LevelFilter, warn}; /// CLI for performing simple interactions against a Tendermint node's RPC. /// @@ -249,7 +253,7 @@ fn get_http_proxy_url(url_scheme: Scheme, proxy_url: Option) -> Result, req: Request) -> Result<(), Error> { - let client = match proxy_url { + let mut client = match proxy_url { Some(proxy_url) => { info!( "Using HTTP client with proxy {} to submit request to {}", @@ -263,6 +267,11 @@ async fn http_request(url: Url, proxy_url: Option, req: Request) -> Result< }, }?; + let status = client.status().await?; + let compat_mode = CompatMode::from_version(status.node_info.version)?; + debug!("Using compatibility mode {}", compat_mode); + client.set_compat_mode(compat_mode); + match req { Request::ClientRequest(r) => client_request(&client, r).await, _ => Err(Error::invalid_params("HTTP/S clients do not support subscription capabilities (please use the WebSocket client instead)".to_owned())) @@ -271,8 +280,7 @@ async fn http_request(url: Url, proxy_url: Option, req: Request) -> Result< async fn websocket_request(url: Url, req: Request) -> Result<(), Error> { info!("Using WebSocket client to submit request to: {}", url); - let (client, driver) = WebSocketClient::new(url).await?; - let driver_hdl = tokio::spawn(async move { driver.run().await }); + let (client, driver_hdl) = start_websocket_client(url).await?; let result = match req { Request::ClientRequest(r) => client_request(&client, r).await, @@ -283,11 +291,40 @@ async fn websocket_request(url: Url, req: Request) -> Result<(), Error> { } => subscription_client_request(&client, query, max_events, max_time).await, }; - client.close()?; - driver_hdl.await.map_err(Error::join)??; + stop_websocket_client(client, driver_hdl).await?; result } +async fn start_websocket_client( + url: Url, +) -> Result<(WebSocketClient, JoinHandle>), Error> { + let (client, driver) = WebSocketClient::new(url.clone()).await?; + let driver_hdl = tokio::spawn(async move { driver.run().await }); + let status = client.status().await?; + let compat_mode = CompatMode::from_version(status.node_info.version)?; + if compat_mode == CompatMode::latest() { + debug!("Using compatibility mode {}", compat_mode); + Ok((client, driver_hdl)) + } else { + debug!("Reconnecting with compatibility mode {}", compat_mode); + stop_websocket_client(client, driver_hdl).await?; + let (client, driver) = WebSocketClient::builder(url.try_into()?) + .compat_mode(compat_mode) + .build() + .await?; + let driver_hdl = tokio::spawn(async move { driver.run().await }); + Ok((client, driver_hdl)) + } +} + +async fn stop_websocket_client( + client: WebSocketClient, + driver_hdl: JoinHandle>, +) -> Result<(), Error> { + client.close()?; + driver_hdl.await.map_err(Error::join)? +} + async fn client_request(client: &C, req: ClientRequest) -> Result<(), Error> where C: Client + Sync, @@ -467,6 +504,7 @@ async fn recv_events_with_timeout( } }; let event = result?; + let event: DialectEvent<::Event> = event.into(); println!("{}", serde_json::to_string_pretty(&event).map_err(Error::serde)?); event_count += 1; if let Some(me) = max_events { @@ -488,6 +526,7 @@ async fn recv_events(mut subs: Subscription, max_events: Option) -> Result< let mut event_count = 0u64; while let Some(result) = subs.next().await { let event = result?; + let event: DialectEvent<::Event> = event.into(); println!( "{}", serde_json::to_string_pretty(&event).map_err(Error::serde)? diff --git a/rpc/src/client/compat.rs b/rpc/src/client/compat.rs new file mode 100644 index 000000000..ccc698097 --- /dev/null +++ b/rpc/src/client/compat.rs @@ -0,0 +1,98 @@ +//! Support for dynamic compatibility with older protocol versions. + +use core::fmt; + +use tendermint::Version; + +use crate::prelude::*; +use crate::Error; + +/// Protocol compatibility mode for a Tendermint RPC client. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum CompatMode { + /// Use version 0.34 of the protocol. + V0_34, + /// Use version 0.37 of the protocol. + V0_37, +} + +impl Default for CompatMode { + fn default() -> Self { + CompatMode::latest() + } +} + +impl CompatMode { + /// The latest supported version, selected by default. + pub const fn latest() -> Self { + Self::V0_37 + } + + /// Parse the Tendermint version string to determine + /// the compatibility mode. + /// + /// The version can be obtained by querying the `/status` endpoint. + /// The request and response format of this endpoint is currently the same + /// for all supported RPC dialects, so such a request can be performed + /// before the required compatibility mode is settled upon. + /// + /// Note that this is not fail-proof: the version is reported for a particular + /// client connection, so any other connections to the same URL might not + /// be handled by the same server. In the future, the RPC protocol should + /// follow versioning practices designed to avoid ambiguities with + /// message formats. + pub fn from_version(tendermint_version: Version) -> Result { + let raw_version: String = tendermint_version.into(); + let version = semver::Version::parse(raw_version.trim_start_matches('v')) + .map_err(|_| Error::invalid_tendermint_version(raw_version))?; + + match (version.major, version.minor) { + (0, 34) => Ok(CompatMode::V0_34), + (0, 37) => Ok(CompatMode::V0_37), + _ => Err(Error::unsupported_tendermint_version(version.to_string())), + } + } +} + +impl fmt::Display for CompatMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CompatMode::V0_34 => f.write_str("v0.34"), + CompatMode::V0_37 => f.write_str("v0.37"), + } + } +} + +#[cfg(test)] +mod tests { + use super::CompatMode; + use crate::prelude::*; + use tendermint::Version; + + fn parse_version(s: &str) -> Version { + let json = format!("\"{s}\""); + serde_json::from_str(&json).unwrap() + } + + #[test] + fn test_parse_version_for_compat_mode() { + assert_eq!( + CompatMode::from_version(parse_version("v0.34.16")).unwrap(), + CompatMode::V0_34 + ); + assert_eq!( + CompatMode::from_version(parse_version("v0.37.0-pre1")).unwrap(), + CompatMode::V0_37 + ); + assert_eq!( + CompatMode::from_version(parse_version("v0.37.0")).unwrap(), + CompatMode::V0_37 + ); + let res = CompatMode::from_version(parse_version("v0.38.0")); + assert!(res.is_err()); + let res = CompatMode::from_version(parse_version("v1.0.0")); + assert!(res.is_err()); + let res = CompatMode::from_version(parse_version("poobah")); + assert!(res.is_err()); + } +} diff --git a/rpc/src/client/transport.rs b/rpc/src/client/transport.rs index a9ba2242e..f8859696b 100644 --- a/rpc/src/client/transport.rs +++ b/rpc/src/client/transport.rs @@ -4,6 +4,16 @@ mod auth; pub mod mock; mod router; +macro_rules! perform_with_compat { + ($self:expr, $request:expr) => {{ + let request = $request; + match $self.compat { + CompatMode::V0_37 => $self.perform(request).await, + CompatMode::V0_34 => $self.perform_v0_34(request).await, + } + }}; +} + #[cfg(feature = "http-client")] pub mod http; #[cfg(feature = "websocket-client")] diff --git a/rpc/src/client/transport/http.rs b/rpc/src/client/transport/http.rs index fd7779ec2..648aa859f 100644 --- a/rpc/src/client/transport/http.rs +++ b/rpc/src/client/transport/http.rs @@ -6,9 +6,18 @@ use core::{ }; use async_trait::async_trait; + +use tendermint::{block::Height, Hash}; use tendermint_config::net; -use crate::{client::Client, prelude::*, Error, Scheme, SimpleRequest, Url}; +use crate::dialect::v0_34; +use crate::prelude::*; +use crate::{ + client::{Client, CompatMode}, + endpoint, + query::Query, + Error, Order, Scheme, SimpleRequest, Url, +}; /// A JSON-RPC/HTTP Tendermint RPC client (implements [`crate::Client`]). /// @@ -39,6 +48,60 @@ use crate::{client::Client, prelude::*, Error, Scheme, SimpleRequest, Url}; #[derive(Debug, Clone)] pub struct HttpClient { inner: sealed::HttpClient, + compat: CompatMode, +} + +/// The builder pattern constructor for [`HttpClient`]. +pub struct Builder { + url: HttpClientUrl, + compat: CompatMode, + proxy_url: Option, +} + +impl Builder { + /// Use the specified compatibility mode for the Tendermint RPC protocol. + /// + /// The default is the latest protocol version supported by this crate. + pub fn compat_mode(mut self, mode: CompatMode) -> Self { + self.compat = mode; + self + } + + /// Specify the URL of a proxy server for the client to connect through. + /// + /// If the RPC endpoint is secured (HTTPS), the proxy will automatically + /// attempt to connect using the [HTTP CONNECT] method. + /// + /// [HTTP CONNECT]: https://en.wikipedia.org/wiki/HTTP_tunnel + pub fn proxy_url(mut self, url: HttpClientUrl) -> Self { + self.proxy_url = Some(url); + self + } + + /// Try to create a client with the options specified for this builder. + pub fn build(self) -> Result { + match self.proxy_url { + None => Ok(HttpClient { + inner: if self.url.0.is_secure() { + sealed::HttpClient::new_https(self.url.try_into()?) + } else { + sealed::HttpClient::new_http(self.url.try_into()?) + }, + compat: self.compat, + }), + Some(proxy_url) => Ok(HttpClient { + inner: if proxy_url.0.is_secure() { + sealed::HttpClient::new_https_proxy( + self.url.try_into()?, + proxy_url.try_into()?, + )? + } else { + sealed::HttpClient::new_http_proxy(self.url.try_into()?, proxy_url.try_into()?)? + }, + compat: self.compat, + }), + } + } } impl HttpClient { @@ -55,6 +118,7 @@ impl HttpClient { } else { sealed::HttpClient::new_http(url.try_into()?) }, + compat: Default::default(), }) } @@ -71,25 +135,118 @@ impl HttpClient { P: TryInto, { let url = url.try_into()?; - let proxy_url = proxy_url.try_into()?; - Ok(Self { - inner: if proxy_url.0.is_secure() { - sealed::HttpClient::new_https_proxy(url.try_into()?, proxy_url.try_into()?)? - } else { - sealed::HttpClient::new_http_proxy(url.try_into()?, proxy_url.try_into()?)? - }, - }) + Self::builder(url).proxy_url(proxy_url.try_into()?).build() + } + + /// Initiate a builder for a Tendermint RPC HTTP/S client connecting + /// to the given URL, so that more configuration options can be specified + /// with the builder. + pub fn builder(url: HttpClientUrl) -> Builder { + Builder { + url, + compat: Default::default(), + proxy_url: None, + } + } + + /// Set compatibility mode on the instantiated client. + /// + /// As the HTTP client is stateless and does not support subscriptions, + /// the protocol version it uses can be changed at will, for example, + /// as a result of version discovery over the `/status` endpoint. + pub fn set_compat_mode(&mut self, compat: CompatMode) { + self.compat = compat; + } + + async fn perform_v0_34(&self, request: R) -> Result + where + R: SimpleRequest, + { + self.inner.perform(request).await } } #[async_trait] impl Client for HttpClient { - async fn perform(&self, request: R) -> Result + async fn perform(&self, request: R) -> Result where R: SimpleRequest, { self.inner.perform(request).await } + + async fn block_results(&self, height: H) -> Result + where + H: Into + Send, + { + perform_with_compat!(self, endpoint::block_results::Request::new(height.into())) + } + + async fn header(&self, height: H) -> Result + where + H: Into + Send, + { + let height = height.into(); + match self.compat { + CompatMode::V0_37 => self.perform(endpoint::header::Request::new(height)).await, + CompatMode::V0_34 => { + // Back-fill with a request to /block endpoint and + // taking just the header from the response. + let resp = self + .perform_v0_34(endpoint::block::Request::new(height)) + .await?; + Ok(resp.into()) + }, + } + } + + async fn header_by_hash( + &self, + hash: Hash, + ) -> Result { + match self.compat { + CompatMode::V0_37 => { + self.perform(endpoint::header_by_hash::Request::new(hash)) + .await + }, + CompatMode::V0_34 => { + // Back-fill with a request to /block_by_hash endpoint and + // taking just the header from the response. + let resp = self + .perform_v0_34(endpoint::block_by_hash::Request::new(hash)) + .await?; + Ok(resp.into()) + }, + } + } + + async fn tx(&self, hash: Hash, prove: bool) -> Result { + perform_with_compat!(self, endpoint::tx::Request::new(hash, prove)) + } + + async fn tx_search( + &self, + query: Query, + prove: bool, + page: u32, + per_page: u8, + order: Order, + ) -> Result { + perform_with_compat!( + self, + endpoint::tx_search::Request::new(query, prove, page, per_page, order) + ) + } + + async fn broadcast_tx_commit( + &self, + tx: T, + ) -> Result + where + T: Into> + Send, + { + perform_with_compat!(self, endpoint::broadcast::tx_commit::Request::new(tx)) + } } /// A URL limited to use with HTTP clients. @@ -167,7 +324,10 @@ mod sealed { use hyper_proxy::{Intercept, Proxy, ProxyConnector}; use hyper_rustls::HttpsConnector; - use crate::{client::transport::auth::authorize, prelude::*, Error, Response, SimpleRequest}; + use crate::prelude::*; + use crate::{ + client::transport::auth::authorize, dialect::Dialect, Error, Response, SimpleRequest, + }; /// A wrapper for a `hyper`-based client, generic over the connector type. #[derive(Debug, Clone)] @@ -186,24 +346,26 @@ mod sealed { where C: Connect + Clone + Send + Sync + 'static, { - pub async fn perform(&self, request: R) -> Result + pub async fn perform(&self, request: R) -> Result where - R: SimpleRequest, + R: SimpleRequest, + S: Dialect, { let request = self.build_request(request)?; let response = self.inner.request(request).await.map_err(Error::hyper)?; let response_body = response_to_string(response).await?; tracing::debug!("Incoming response: {}", response_body); - R::Response::from_string(&response_body) + R::Response::from_string(&response_body).map(Into::into) } } impl HyperClient { /// Build a request using the given Tendermint RPC request. - pub fn build_request( - &self, - request: R, - ) -> Result, Error> { + pub fn build_request(&self, request: R) -> Result, Error> + where + R: SimpleRequest, + S: Dialect, + { let request_body = request.into_json(); tracing::debug!("Outgoing request: {}", request_body); @@ -280,9 +442,10 @@ mod sealed { ))) } - pub async fn perform(&self, request: R) -> Result + pub async fn perform(&self, request: R) -> Result where - R: SimpleRequest, + R: SimpleRequest, + S: Dialect, { match self { HttpClient::Http(c) => c.perform(request).await, @@ -314,6 +477,7 @@ mod tests { use hyper::Body; use super::sealed::HyperClient; + use crate::dialect::LatestDialect; use crate::endpoint::abci_info; fn authorization(req: &Request) -> Option<&str> { @@ -327,7 +491,8 @@ mod tests { let uri = Uri::from_str("http://example.com").unwrap(); let inner = hyper::Client::new(); let client = HyperClient::new(uri, inner); - let req = client.build_request(abci_info::Request).unwrap(); + let req = + HyperClient::build_request::<_, LatestDialect>(&client, abci_info::Request).unwrap(); assert_eq!(authorization(&req), None); } @@ -337,7 +502,8 @@ mod tests { let uri = Uri::from_str("http://toto:tata@example.com").unwrap(); let inner = hyper::Client::new(); let client = HyperClient::new(uri, inner); - let req = client.build_request(abci_info::Request).unwrap(); + let req = + HyperClient::build_request::<_, LatestDialect>(&client, abci_info::Request).unwrap(); assert_eq!(authorization(&req), Some("Basic dG90bzp0YXRh")); } diff --git a/rpc/src/client/transport/mock.rs b/rpc/src/client/transport/mock.rs index a35feaf5c..987885779 100644 --- a/rpc/src/client/transport/mock.rs +++ b/rpc/src/client/transport/mock.rs @@ -4,17 +4,20 @@ use alloc::collections::BTreeMap as HashMap; use async_trait::async_trait; +use crate::dialect::{v0_37, Dialect}; use crate::{ client::{ subscription::SubscriptionTx, sync::{unbounded, ChannelRx, ChannelTx}, transport::router::SubscriptionRouter, + Client, }, event::Event, prelude::*, query::Query, + request::SimpleRequest, utils::uuid_str, - Client, Error, Method, Request, Response, Subscription, SubscriptionClient, + Error, Method, Request, Response, Subscription, SubscriptionClient, }; /// A mock client implementation for use in testing. @@ -60,13 +63,14 @@ pub struct MockClient { #[async_trait] impl Client for MockClient { - async fn perform(&self, request: R) -> Result + async fn perform(&self, request: R) -> Result where - R: Request, + R: SimpleRequest, { self.matcher .response_for(request) .ok_or_else(Error::mismatch_response)? + .map(Into::into) } } @@ -196,9 +200,10 @@ impl MockClientDriver { /// [`MockClient`]: struct.MockClient.html pub trait MockRequestMatcher: Send + Sync { /// Provide the corresponding response for the given request (if any). - fn response_for(&self, request: R) -> Option> + fn response_for(&self, request: R) -> Option> where - R: Request; + R: Request, + S: Dialect; } /// Provides a simple [`MockRequestMatcher`] implementation that simply maps @@ -211,9 +216,10 @@ pub struct MockRequestMethodMatcher { } impl MockRequestMatcher for MockRequestMethodMatcher { - fn response_for(&self, request: R) -> Option> + fn response_for(&self, request: R) -> Option> where - R: Request, + R: Request, + S: Dialect, { self.mappings.get(&request.method()).map(|res| match res { Ok(json) => R::Response::from_string(json), @@ -245,73 +251,154 @@ mod test { use super::*; use crate::query::EventType; - async fn read_json_fixture(name: &str) -> String { + async fn read_json_fixture(version: &str, name: &str) -> String { fs::read_to_string( - PathBuf::from("./tests/kvstore_fixtures/incoming/").join(name.to_owned() + ".json"), + PathBuf::from("./tests/kvstore_fixtures") + .join(version) + .join("incoming") + .join(name.to_owned() + ".json"), ) .await .unwrap() } - async fn read_event(name: &str) -> Event { - Event::from_string(read_json_fixture(name).await).unwrap() - } + mod v0_34 { + use super::*; + use crate::dialect::v0_34::Event as RpcEvent; + use crate::event::DialectEvent; - #[tokio::test] - async fn mock_client() { - let abci_info_fixture = read_json_fixture("abci_info").await; - let block_fixture = read_json_fixture("block_at_height_10").await; - let matcher = MockRequestMethodMatcher::default() - .map(Method::AbciInfo, Ok(abci_info_fixture)) - .map(Method::Block, Ok(block_fixture)); - let (client, driver) = MockClient::new(matcher); - let driver_hdl = tokio::spawn(async move { driver.run().await }); - - let abci_info = client.abci_info().await.unwrap(); - assert_eq!("{\"size\":0}".to_string(), abci_info.data); - - let block = client.block(Height::from(10_u32)).await.unwrap().block; - assert_eq!(Height::from(10_u32), block.header.height); - assert_eq!("dockerchain".parse::().unwrap(), block.header.chain_id); - - client.close(); - driver_hdl.await.unwrap().unwrap(); - } + async fn read_event(name: &str) -> Event { + let msg = DialectEvent::::from_string(read_json_fixture("v0_34", name).await) + .unwrap(); + msg.into() + } + + #[tokio::test] + async fn mock_client() { + let abci_info_fixture = read_json_fixture("v0_34", "abci_info").await; + let block_fixture = read_json_fixture("v0_34", "block_at_height_10").await; + let matcher = MockRequestMethodMatcher::default() + .map(Method::AbciInfo, Ok(abci_info_fixture)) + .map(Method::Block, Ok(block_fixture)); + let (client, driver) = MockClient::new(matcher); + let driver_hdl = tokio::spawn(async move { driver.run().await }); + + let abci_info = client.abci_info().await.unwrap(); + assert_eq!("{\"size\":0}".to_string(), abci_info.data); + + let block = client.block(Height::from(10_u32)).await.unwrap().block; + assert_eq!(Height::from(10_u32), block.header.height); + assert_eq!("dockerchain".parse::().unwrap(), block.header.chain_id); + + client.close(); + driver_hdl.await.unwrap().unwrap(); + } + + #[tokio::test] + async fn mock_subscription_client() { + let (client, driver) = MockClient::new(MockRequestMethodMatcher::default()); + let driver_hdl = tokio::spawn(async move { driver.run().await }); + + let event1 = read_event("subscribe_newblock_0").await; + let event2 = read_event("subscribe_newblock_1").await; + let event3 = read_event("subscribe_newblock_2").await; + let events = vec![event1, event2, event3]; + + let subs1 = client.subscribe(EventType::NewBlock.into()).await.unwrap(); + let subs2 = client.subscribe(EventType::NewBlock.into()).await.unwrap(); + assert_ne!(subs1.id().to_string(), subs2.id().to_string()); + + // We can do this because the underlying channels can buffer the + // messages as we publish them. + let subs1_events = subs1.take(3); + let subs2_events = subs2.take(3); + for ev in &events { + client.publish(ev); + } + + // Here each subscription's channel is drained. + let subs1_events = subs1_events.collect::>>().await; + let subs2_events = subs2_events.collect::>>().await; + + assert_eq!(3, subs1_events.len()); + assert_eq!(3, subs2_events.len()); + + for i in 0..3 { + assert!(events[i].eq(subs1_events[i].as_ref().unwrap())); + } - #[tokio::test] - async fn mock_subscription_client() { - let (client, driver) = MockClient::new(MockRequestMethodMatcher::default()); - let driver_hdl = tokio::spawn(async move { driver.run().await }); - - let event1 = read_event("subscribe_newblock_0").await; - let event2 = read_event("subscribe_newblock_1").await; - let event3 = read_event("subscribe_newblock_2").await; - let events = vec![event1, event2, event3]; - - let subs1 = client.subscribe(EventType::NewBlock.into()).await.unwrap(); - let subs2 = client.subscribe(EventType::NewBlock.into()).await.unwrap(); - assert_ne!(subs1.id().to_string(), subs2.id().to_string()); - - // We can do this because the underlying channels can buffer the - // messages as we publish them. - let subs1_events = subs1.take(3); - let subs2_events = subs2.take(3); - for ev in &events { - client.publish(ev); + client.close(); + driver_hdl.await.unwrap().unwrap(); } + } - // Here each subscription's channel is drained. - let subs1_events = subs1_events.collect::>>().await; - let subs2_events = subs2_events.collect::>>().await; + mod v0_37 { + use super::*; + use crate::dialect::v0_37::Event as RpcEvent; + use crate::event::DialectEvent; - assert_eq!(3, subs1_events.len()); - assert_eq!(3, subs2_events.len()); + async fn read_event(name: &str) -> Event { + let msg = DialectEvent::::from_string(read_json_fixture("v0_37", name).await) + .unwrap(); + msg.into() + } - for i in 0..3 { - assert!(events[i].eq(subs1_events[i].as_ref().unwrap())); + #[tokio::test] + async fn mock_client() { + let abci_info_fixture = read_json_fixture("v0_37", "abci_info").await; + let block_fixture = read_json_fixture("v0_37", "block_at_height_10").await; + let matcher = MockRequestMethodMatcher::default() + .map(Method::AbciInfo, Ok(abci_info_fixture)) + .map(Method::Block, Ok(block_fixture)); + let (client, driver) = MockClient::new(matcher); + let driver_hdl = tokio::spawn(async move { driver.run().await }); + + let abci_info = client.abci_info().await.unwrap(); + assert_eq!("{\"size\":9}".to_string(), abci_info.data); + + let block = client.block(Height::from(10_u32)).await.unwrap().block; + assert_eq!(Height::from(10_u32), block.header.height); + assert_eq!("dockerchain".parse::().unwrap(), block.header.chain_id); + + client.close(); + driver_hdl.await.unwrap().unwrap(); } - client.close(); - driver_hdl.await.unwrap().unwrap(); + #[tokio::test] + async fn mock_subscription_client() { + let (client, driver) = MockClient::new(MockRequestMethodMatcher::default()); + let driver_hdl = tokio::spawn(async move { driver.run().await }); + + let event1 = read_event("subscribe_newblock_0").await; + let event2 = read_event("subscribe_newblock_1").await; + let event3 = read_event("subscribe_newblock_2").await; + let events = vec![event1, event2, event3]; + + let subs1 = client.subscribe(EventType::NewBlock.into()).await.unwrap(); + let subs2 = client.subscribe(EventType::NewBlock.into()).await.unwrap(); + assert_ne!(subs1.id().to_string(), subs2.id().to_string()); + + // We can do this because the underlying channels can buffer the + // messages as we publish them. + let subs1_events = subs1.take(3); + let subs2_events = subs2.take(3); + for ev in &events { + client.publish(ev); + } + + // Here each subscription's channel is drained. + let subs1_events = subs1_events.collect::>>().await; + let subs2_events = subs2_events.collect::>>().await; + + assert_eq!(3, subs1_events.len()); + assert_eq!(3, subs2_events.len()); + + for i in 0..3 { + assert!(events[i].eq(subs1_events[i].as_ref().unwrap())); + } + + client.close(); + driver_hdl.await.unwrap().unwrap(); + } } } diff --git a/rpc/src/client/transport/router.rs b/rpc/src/client/transport/router.rs index 906885a22..985492069 100644 --- a/rpc/src/client/transport/router.rs +++ b/rpc/src/client/transport/router.rs @@ -148,21 +148,17 @@ mod test { utils::uuid_str, }; - async fn read_json_fixture(name: &str) -> String { + async fn read_json_fixture(version: &str, name: &str) -> String { fs::read_to_string( - PathBuf::from("./tests/kvstore_fixtures/incoming/").join(name.to_owned() + ".json"), + PathBuf::from("./tests/kvstore_fixtures") + .join(version) + .join("incoming") + .join(name.to_owned() + ".json"), ) .await .unwrap() } - async fn read_event(name: &str) -> Event { - serde_json::from_str::(read_json_fixture(name).await.as_str()) - .unwrap() - .into_result() - .unwrap() - } - async fn must_recv(ch: &mut ChannelRx, timeout_ms: u64) -> T { let delay = time::sleep(Duration::from_millis(timeout_ms)); tokio::select! { @@ -182,37 +178,101 @@ mod test { } } - #[tokio::test] - async fn router_basic_pub_sub() { - let mut router = SubscriptionRouter::default(); - - let (subs1_id, subs2_id, subs3_id) = (uuid_str(), uuid_str(), uuid_str()); - let (subs1_event_tx, mut subs1_event_rx) = unbounded(); - let (subs2_event_tx, mut subs2_event_rx) = unbounded(); - let (subs3_event_tx, mut subs3_event_rx) = unbounded(); - - // Two subscriptions with the same query - router.add(subs1_id, "query1", subs1_event_tx); - router.add(subs2_id, "query1", subs2_event_tx); - // Another subscription with a different query - router.add(subs3_id, "query2", subs3_event_tx); - - let mut ev = read_event("subscribe_newblock_0").await; - ev.query = "query1".into(); - router.publish_event(ev.clone()); - - let subs1_ev = must_recv(&mut subs1_event_rx, 500).await.unwrap(); - let subs2_ev = must_recv(&mut subs2_event_rx, 500).await.unwrap(); - must_not_recv(&mut subs3_event_rx, 50).await; - assert_eq!(ev, subs1_ev); - assert_eq!(ev, subs2_ev); - - ev.query = "query2".into(); - router.publish_event(ev.clone()); - - must_not_recv(&mut subs1_event_rx, 50).await; - must_not_recv(&mut subs2_event_rx, 50).await; - let subs3_ev = must_recv(&mut subs3_event_rx, 500).await.unwrap(); - assert_eq!(ev, subs3_ev); + mod v0_34 { + use super::*; + use crate::dialect::v0_34::Event as RpcEvent; + + async fn read_event(name: &str) -> Event { + serde_json::from_str::>( + read_json_fixture("v0_34", name).await.as_str(), + ) + .unwrap() + .into_result() + .unwrap() + .into() + } + + #[tokio::test] + async fn router_basic_pub_sub() { + let mut router = SubscriptionRouter::default(); + + let (subs1_id, subs2_id, subs3_id) = (uuid_str(), uuid_str(), uuid_str()); + let (subs1_event_tx, mut subs1_event_rx) = unbounded(); + let (subs2_event_tx, mut subs2_event_rx) = unbounded(); + let (subs3_event_tx, mut subs3_event_rx) = unbounded(); + + // Two subscriptions with the same query + router.add(subs1_id, "query1", subs1_event_tx); + router.add(subs2_id, "query1", subs2_event_tx); + // Another subscription with a different query + router.add(subs3_id, "query2", subs3_event_tx); + + let mut ev = read_event("subscribe_newblock_0").await; + ev.query = "query1".into(); + router.publish_event(ev.clone()); + + let subs1_ev = must_recv(&mut subs1_event_rx, 500).await.unwrap(); + let subs2_ev = must_recv(&mut subs2_event_rx, 500).await.unwrap(); + must_not_recv(&mut subs3_event_rx, 50).await; + assert_eq!(ev, subs1_ev); + assert_eq!(ev, subs2_ev); + + ev.query = "query2".into(); + router.publish_event(ev.clone()); + + must_not_recv(&mut subs1_event_rx, 50).await; + must_not_recv(&mut subs2_event_rx, 50).await; + let subs3_ev = must_recv(&mut subs3_event_rx, 500).await.unwrap(); + assert_eq!(ev, subs3_ev); + } + } + + mod v0_37 { + use super::*; + use crate::dialect::v0_37::Event as RpcEvent; + + async fn read_event(name: &str) -> Event { + serde_json::from_str::>( + read_json_fixture("v0_37", name).await.as_str(), + ) + .unwrap() + .into_result() + .unwrap() + .into() + } + + #[tokio::test] + async fn router_basic_pub_sub() { + let mut router = SubscriptionRouter::default(); + + let (subs1_id, subs2_id, subs3_id) = (uuid_str(), uuid_str(), uuid_str()); + let (subs1_event_tx, mut subs1_event_rx) = unbounded(); + let (subs2_event_tx, mut subs2_event_rx) = unbounded(); + let (subs3_event_tx, mut subs3_event_rx) = unbounded(); + + // Two subscriptions with the same query + router.add(subs1_id, "query1", subs1_event_tx); + router.add(subs2_id, "query1", subs2_event_tx); + // Another subscription with a different query + router.add(subs3_id, "query2", subs3_event_tx); + + let mut ev = read_event("subscribe_newblock_0").await; + ev.query = "query1".into(); + router.publish_event(ev.clone()); + + let subs1_ev = must_recv(&mut subs1_event_rx, 500).await.unwrap(); + let subs2_ev = must_recv(&mut subs2_event_rx, 500).await.unwrap(); + must_not_recv(&mut subs3_event_rx, 50).await; + assert_eq!(ev, subs1_ev); + assert_eq!(ev, subs2_ev); + + ev.query = "query2".into(); + router.publish_event(ev.clone()); + + must_not_recv(&mut subs1_event_rx, 50).await; + must_not_recv(&mut subs2_event_rx, 50).await; + let subs3_ev = must_recv(&mut subs3_event_rx, 500).await.unwrap(); + assert_eq!(ev, subs3_ev); + } } } diff --git a/rpc/src/client/transport/websocket.rs b/rpc/src/client/transport/websocket.rs index 3b0debcf5..0c1a710e6 100644 --- a/rpc/src/client/transport/websocket.rs +++ b/rpc/src/client/transport/websocket.rs @@ -1,6 +1,6 @@ //! WebSocket-based clients for accessing Tendermint RPC functionality. -use alloc::{borrow::Cow, collections::BTreeMap as HashMap}; +use alloc::{borrow::Cow, collections::BTreeMap as HashMap, fmt}; use core::{ convert::{TryFrom, TryInto}, ops::Add, @@ -18,24 +18,28 @@ use async_tungstenite::{ }; use futures::{SinkExt, StreamExt}; use serde::{Deserialize, Serialize}; -use tendermint_config::net; use tokio::time::{Duration, Instant}; use tracing::{debug, error}; +use tendermint::{block::Height, Hash}; +use tendermint_config::net; + use super::router::{SubscriptionId, SubscriptionIdRef}; +use crate::dialect::{v0_34, v0_37}; use crate::{ client::{ subscription::SubscriptionTx, sync::{ChannelRx, ChannelTx}, transport::router::{PublishResult, SubscriptionRouter}, + Client, CompatMode, }, - endpoint::{subscribe, unsubscribe}, + endpoint::{self, subscribe, unsubscribe}, error::Error, - event::Event, + event::{DialectEvent, Event}, prelude::*, query::Query, request::Wrapper, - response, Client, Id, Request, Response, Scheme, SimpleRequest, Subscription, + response, Id, Order, Request, Response, Scheme, SimpleRequest, Subscription, SubscriptionClient, Url, }; @@ -137,6 +141,43 @@ pub use async_tungstenite::tungstenite::protocol::WebSocketConfig; #[derive(Debug, Clone)] pub struct WebSocketClient { inner: sealed::WebSocketClient, + compat: CompatMode, +} + +/// The builder pattern constructor for [`WebSocketClient`]. +pub struct Builder { + url: WebSocketClientUrl, + compat: CompatMode, + transport_config: Option, +} + +impl Builder { + /// Use the specified compatibility mode for the Tendermint RPC protocol. + /// + /// The default is the latest protocol version supported by this crate. + pub fn compat_mode(mut self, mode: CompatMode) -> Self { + self.compat = mode; + self + } + + /// Use the specfied low-level WebSocket configuration options. + pub fn config(mut self, config: WebSocketConfig) -> Self { + self.transport_config = Some(config); + self + } + + /// Try to create a client with the options specified for this builder. + pub async fn build(self) -> Result<(WebSocketClient, WebSocketClientDriver), Error> { + let url = self.url.0; + let compat = self.compat; + let (inner, driver) = if url.is_secure() { + sealed::WebSocketClient::new_secure(url, compat, self.transport_config).await? + } else { + sealed::WebSocketClient::new_unsecure(url, compat, self.transport_config).await? + }; + + Ok((WebSocketClient { inner, compat }, driver)) + } } impl WebSocketClient { @@ -148,7 +189,8 @@ impl WebSocketClient { where U: TryInto, { - Self::new_with_config(url, None).await + let url = url.try_into()?; + Self::builder(url).build().await } /// Construct a new WebSocket-based client connecting to the given @@ -157,31 +199,116 @@ impl WebSocketClient { /// Supports both `ws://` and `wss://` protocols. pub async fn new_with_config( url: U, - config: Option, + config: WebSocketConfig, ) -> Result<(Self, WebSocketClientDriver), Error> where U: TryInto, { let url = url.try_into()?; + Self::builder(url).config(config).build().await + } - let (inner, driver) = if url.0.is_secure() { - sealed::WebSocketClient::new_secure(url.0, config).await? - } else { - sealed::WebSocketClient::new_unsecure(url.0, config).await? - }; + /// Initiate a builder for a WebSocket-based client connecting to the given + /// Tendermint node's RPC endpoint. + /// + /// Supports both `ws://` and `wss://` protocols. + pub fn builder(url: WebSocketClientUrl) -> Builder { + Builder { + url, + compat: Default::default(), + transport_config: Default::default(), + } + } - Ok((Self { inner }, driver)) + async fn perform_v0_34(&self, request: R) -> Result + where + R: SimpleRequest, + { + self.inner.perform(request).await } } #[async_trait] impl Client for WebSocketClient { - async fn perform(&self, request: R) -> Result<::Response, Error> + async fn perform(&self, request: R) -> Result where R: SimpleRequest, { self.inner.perform(request).await } + + async fn block_results(&self, height: H) -> Result + where + H: Into + Send, + { + perform_with_compat!(self, endpoint::block_results::Request::new(height.into())) + } + + async fn header(&self, height: H) -> Result + where + H: Into + Send, + { + let height = height.into(); + match self.compat { + CompatMode::V0_37 => self.perform(endpoint::header::Request::new(height)).await, + CompatMode::V0_34 => { + // Back-fill with a request to /block endpoint and + // taking just the header from the response. + let resp = self + .perform_v0_34(endpoint::block::Request::new(height)) + .await?; + Ok(resp.into()) + }, + } + } + + async fn header_by_hash( + &self, + hash: Hash, + ) -> Result { + match self.compat { + CompatMode::V0_37 => { + self.perform(endpoint::header_by_hash::Request::new(hash)) + .await + }, + CompatMode::V0_34 => { + // Back-fill with a request to /block_by_hash endpoint and + // taking just the header from the response. + let resp = self + .perform_v0_34(endpoint::block_by_hash::Request::new(hash)) + .await?; + Ok(resp.into()) + }, + } + } + + async fn tx(&self, hash: Hash, prove: bool) -> Result { + perform_with_compat!(self, endpoint::tx::Request::new(hash, prove)) + } + + async fn tx_search( + &self, + query: Query, + prove: bool, + page: u32, + per_page: u8, + order: Order, + ) -> Result { + perform_with_compat!( + self, + endpoint::tx_search::Request::new(query, prove, page, per_page, order) + ) + } + + async fn broadcast_tx_commit( + &self, + tx: T, + ) -> Result + where + T: Into> + Send, + { + perform_with_compat!(self, endpoint::broadcast::tx_commit::Request::new(tx)) + } } #[async_trait] @@ -202,7 +329,8 @@ impl SubscriptionClient for WebSocketClient { /// A URL limited to use with WebSocket clients. /// /// Facilitates useful type conversions and inferences. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[serde(transparent)] pub struct WebSocketClientUrl(Url); impl TryFrom for WebSocketClientUrl { @@ -227,6 +355,12 @@ impl FromStr for WebSocketClientUrl { } } +impl fmt::Display for WebSocketClientUrl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + impl TryFrom<&str> for WebSocketClientUrl { type Error = Error; @@ -261,19 +395,21 @@ impl From for Url { mod sealed { use async_tungstenite::{ tokio::{connect_async_with_config, connect_async_with_tls_connector_and_config}, - tungstenite::{client::IntoClientRequest, protocol::WebSocketConfig}, + tungstenite::client::IntoClientRequest, }; use tracing::debug; use super::{ DriverCommand, SimpleRequestCommand, SubscribeCommand, UnsubscribeCommand, - WebSocketClientDriver, + WebSocketClientDriver, WebSocketConfig, }; use crate::{ client::{ sync::{unbounded, ChannelTx}, transport::auth::authorize, + CompatMode, }, + dialect::Dialect, prelude::*, query::Query, request::Wrapper, @@ -314,6 +450,7 @@ mod sealed { /// doesn't block the client. pub async fn new( url: Url, + compat: CompatMode, config: Option, ) -> Result<(Self, WebSocketClientDriver), Error> { debug!("Connecting to unsecure WebSocket endpoint: {}", url); @@ -323,7 +460,7 @@ mod sealed { .map_err(Error::tungstenite)?; let (cmd_tx, cmd_rx) = unbounded(); - let driver = WebSocketClientDriver::new(stream, cmd_rx); + let driver = WebSocketClientDriver::new(stream, cmd_rx, compat); let client = Self { cmd_tx, _client_type: Default::default(), @@ -345,6 +482,7 @@ mod sealed { /// doesn't block the client. pub async fn new( url: Url, + compat: CompatMode, config: Option, ) -> Result<(Self, WebSocketClientDriver), Error> { debug!("Connecting to secure WebSocket endpoint: {}", url); @@ -357,7 +495,7 @@ mod sealed { .map_err(Error::tungstenite)?; let (cmd_tx, cmd_rx) = unbounded(); - let driver = WebSocketClientDriver::new(stream, cmd_rx); + let driver = WebSocketClientDriver::new(stream, cmd_rx, compat); let client = Self { cmd_tx, _client_type: Default::default(), @@ -372,9 +510,17 @@ mod sealed { self.cmd_tx.send(cmd) } - pub async fn perform(&self, request: R) -> Result + /// Signals to the driver that it must terminate. + pub fn close(self) -> Result<(), Error> { + self.send_cmd(DriverCommand::Terminate) + } + } + + impl AsyncTungsteniteClient { + pub async fn perform(&self, request: R) -> Result where - R: SimpleRequest, + R: SimpleRequest, + S: Dialect, { let wrapper = Wrapper::new(request); let id = wrapper.id().to_string(); @@ -396,7 +542,7 @@ mod sealed { tracing::debug!("Incoming response: {}", response); - R::Response::from_string(response) + R::Response::from_string(response).map(Into::into) } pub async fn subscribe(&self, query: Query) -> Result { @@ -428,11 +574,6 @@ mod sealed { })??; Ok(()) } - - /// Signals to the driver that it must terminate. - pub fn close(self) -> Result<(), Error> { - self.send_cmd(DriverCommand::Terminate) - } } /// Allows us to erase the type signatures associated with the different @@ -446,23 +587,37 @@ mod sealed { impl WebSocketClient { pub async fn new_unsecure( url: Url, + compat: CompatMode, config: Option, ) -> Result<(Self, WebSocketClientDriver), Error> { - let (client, driver) = AsyncTungsteniteClient::::new(url, config).await?; + let (client, driver) = + AsyncTungsteniteClient::::new(url, compat, config).await?; Ok((Self::Unsecure(client), driver)) } pub async fn new_secure( url: Url, + compat: CompatMode, config: Option, ) -> Result<(Self, WebSocketClientDriver), Error> { - let (client, driver) = AsyncTungsteniteClient::::new(url, config).await?; + let (client, driver) = + AsyncTungsteniteClient::::new(url, compat, config).await?; Ok((Self::Secure(client), driver)) } - pub async fn perform(&self, request: R) -> Result + pub fn close(self) -> Result<(), Error> { + match self { + WebSocketClient::Unsecure(c) => c.close(), + WebSocketClient::Secure(c) => c.close(), + } + } + } + + impl WebSocketClient { + pub async fn perform(&self, request: R) -> Result where - R: SimpleRequest, + R: SimpleRequest, + S: Dialect, { match self { WebSocketClient::Unsecure(c) => c.perform(request).await, @@ -483,13 +638,6 @@ mod sealed { WebSocketClient::Secure(c) => c.unsubscribe(query).await, } } - - pub fn close(self) -> Result<(), Error> { - match self { - WebSocketClient::Unsecure(c) => c.close(), - WebSocketClient::Secure(c) => c.close(), - } - } } use async_tungstenite::tungstenite; @@ -589,18 +737,44 @@ pub struct WebSocketClientDriver { // Commands we've received but have not yet completed, indexed by their ID. // A Terminate command is executed immediately. pending_commands: HashMap, + // The compatibility mode directing how to parse subscription events. + compat: CompatMode, } impl WebSocketClientDriver { - fn new(stream: WebSocketStream, cmd_rx: ChannelRx) -> Self { + fn new( + stream: WebSocketStream, + cmd_rx: ChannelRx, + compat: CompatMode, + ) -> Self { Self { stream, router: SubscriptionRouter::default(), cmd_rx, pending_commands: HashMap::new(), + compat, } } + async fn send_msg(&mut self, msg: Message) -> Result<(), Error> { + self.stream.send(msg).await.map_err(|e| { + Error::web_socket("failed to write to WebSocket connection".to_string(), e) + }) + } + + async fn simple_request(&mut self, cmd: SimpleRequestCommand) -> Result<(), Error> { + if let Err(e) = self + .send_msg(Message::Text(cmd.wrapped_request.clone())) + .await + { + cmd.response_tx.send(Err(e.clone()))?; + return Err(e); + } + self.pending_commands + .insert(cmd.id.clone(), DriverCommand::SimpleRequest(cmd)); + Ok(()) + } + /// Executes the WebSocket driver, which manages the underlying WebSocket /// transport. pub async fn run(mut self) -> Result<(), Error> { @@ -640,12 +814,6 @@ impl WebSocketClientDriver { } } - async fn send_msg(&mut self, msg: Message) -> Result<(), Error> { - self.stream.send(msg).await.map_err(|e| { - Error::web_socket("failed to write to WebSocket connection".to_string(), e) - }) - } - async fn send_request(&mut self, wrapper: Wrapper) -> Result<(), Error> where R: Request, @@ -705,19 +873,6 @@ impl WebSocketClientDriver { Ok(()) } - async fn simple_request(&mut self, cmd: SimpleRequestCommand) -> Result<(), Error> { - if let Err(e) = self - .send_msg(Message::Text(cmd.wrapped_request.clone())) - .await - { - cmd.response_tx.send(Err(e.clone()))?; - return Err(e); - } - self.pending_commands - .insert(cmd.id.clone(), DriverCommand::SimpleRequest(cmd)); - Ok(()) - } - async fn handle_incoming_msg(&mut self, msg: Message) -> Result<(), Error> { match msg { Message::Text(s) => self.handle_text_msg(s).await, @@ -727,7 +882,12 @@ impl WebSocketClientDriver { } async fn handle_text_msg(&mut self, msg: String) -> Result<(), Error> { - if let Ok(ev) = Event::from_string(&msg) { + let parse_res = match self.compat { + CompatMode::V0_37 => DialectEvent::::from_string(&msg).map(Into::into), + CompatMode::V0_34 => DialectEvent::::from_string(&msg).map(Into::into), + }; + if let Ok(ev) = parse_res { + debug!("JSON-RPC event: {}", msg); self.publish_event(ev).await; return Ok(()); } @@ -864,7 +1024,7 @@ mod test { }; use super::*; - use crate::{client::sync::unbounded, query::EventType, request, Id, Method}; + use crate::{client::sync::unbounded, dialect, query::EventType, request, Id, Method}; // Interface to a driver that manages all incoming WebSocket connections. struct TestServer { @@ -875,7 +1035,7 @@ mod test { } impl TestServer { - async fn new(addr: &str) -> Self { + async fn new(addr: &str, compat: CompatMode) -> Self { let listener = TcpListener::bind(addr).await.unwrap(); let local_addr = listener.local_addr().unwrap(); let node_addr = net::Address::Tcp { @@ -885,7 +1045,7 @@ mod test { }; let (terminate_tx, terminate_rx) = unbounded(); let (event_tx, event_rx) = unbounded(); - let driver = TestServerDriver::new(listener, event_rx, terminate_rx); + let driver = TestServerDriver::new(listener, compat, event_rx, terminate_rx); let driver_hdl = tokio::spawn(async move { driver.run().await }); Self { node_addr, @@ -908,6 +1068,7 @@ mod test { // Manages all incoming WebSocket connections. struct TestServerDriver { listener: TcpListener, + compat: CompatMode, event_rx: ChannelRx, terminate_rx: ChannelRx>, handlers: Vec, @@ -916,11 +1077,13 @@ mod test { impl TestServerDriver { fn new( listener: TcpListener, + compat: CompatMode, event_rx: ChannelRx, terminate_rx: ChannelRx>, ) -> Self { Self { listener, + compat, event_rx, terminate_rx, handlers: Vec::new(), @@ -952,7 +1115,8 @@ mod test { } async fn handle_incoming(&mut self, stream: TcpStream) { - self.handlers.push(TestServerHandler::new(stream).await); + self.handlers + .push(TestServerHandler::new(stream, self.compat).await); } async fn terminate(&mut self) { @@ -975,12 +1139,12 @@ mod test { } impl TestServerHandler { - async fn new(stream: TcpStream) -> Self { + async fn new(stream: TcpStream, compat: CompatMode) -> Self { let conn: WebSocketStream> = accept_async(stream).await.unwrap(); let (terminate_tx, terminate_rx) = unbounded(); let (event_tx, event_rx) = unbounded(); - let driver = TestServerHandlerDriver::new(conn, event_rx, terminate_rx); + let driver = TestServerHandlerDriver::new(conn, compat, event_rx, terminate_rx); let driver_hdl = tokio::spawn(async move { driver.run().await }); Self { driver_hdl, @@ -1002,6 +1166,7 @@ mod test { // Manages interaction with a single incoming WebSocket connection. struct TestServerHandlerDriver { conn: WebSocketStream>, + compat: CompatMode, event_rx: ChannelRx, terminate_rx: ChannelRx>, // A mapping of subscription queries to subscription IDs for this @@ -1012,11 +1177,13 @@ mod test { impl TestServerHandlerDriver { fn new( conn: WebSocketStream>, + compat: CompatMode, event_rx: ChannelRx, terminate_rx: ChannelRx>, ) -> Self { Self { conn, + compat, event_rx, terminate_rx, subscriptions: HashMap::new(), @@ -1042,10 +1209,19 @@ mod test { async fn publish_event(&mut self, ev: Event) { let subs_id = match self.subscriptions.get(&ev.query) { - Some(id) => id.clone(), + Some(id) => Id::Str(id.clone()), None => return, }; - self.send(Id::Str(subs_id), ev).await; + match self.compat { + CompatMode::V0_37 => { + let ev: DialectEvent = ev.into(); + self.send(subs_id, ev).await; + }, + CompatMode::V0_34 => { + let ev: DialectEvent = ev.into(); + self.send(subs_id, ev).await; + }, + } } async fn handle_incoming_msg(&mut self, msg: Message) -> Option> { @@ -1144,68 +1320,148 @@ mod test { } } - async fn read_json_fixture(name: &str) -> String { + async fn read_json_fixture(version: &str, name: &str) -> String { fs::read_to_string( - PathBuf::from("./tests/kvstore_fixtures/incoming/").join(name.to_owned() + ".json"), + PathBuf::from("./tests/kvstore_fixtures") + .join(version) + .join("incoming") + .join(name.to_owned() + ".json"), ) .await .unwrap() } - async fn read_event(name: &str) -> Event { - Event::from_string(read_json_fixture(name).await).unwrap() - } + mod v0_34 { + use super::*; + use crate::dialect::v0_34::Event as RpcEvent; - #[tokio::test] - async fn websocket_client_happy_path() { - let event1 = read_event("subscribe_newblock_0").await; - let event2 = read_event("subscribe_newblock_1").await; - let event3 = read_event("subscribe_newblock_2").await; - let test_events = vec![event1, event2, event3]; - - println!("Starting WebSocket server..."); - let mut server = TestServer::new("127.0.0.1:0").await; - println!("Creating client RPC WebSocket connection..."); - let (client, driver) = WebSocketClient::new(server.node_addr.clone()) - .await - .unwrap(); - let driver_handle = tokio::spawn(async move { driver.run().await }); - - println!("Initiating subscription for new blocks..."); - let mut subs = client.subscribe(EventType::NewBlock.into()).await.unwrap(); - - // Collect all the events from the subscription. - let subs_collector_hdl = tokio::spawn(async move { - let mut results = Vec::new(); - while let Some(res) = subs.next().await { - results.push(res); - if results.len() == 3 { - break; + async fn read_event(name: &str) -> Event { + DialectEvent::::from_string(read_json_fixture("v0_34", name).await) + .unwrap() + .into() + } + + #[tokio::test] + async fn websocket_client_happy_path() { + let event1 = read_event("subscribe_newblock_0").await; + let event2 = read_event("subscribe_newblock_1").await; + let event3 = read_event("subscribe_newblock_2").await; + let test_events = vec![event1, event2, event3]; + + println!("Starting WebSocket server..."); + let mut server = TestServer::new("127.0.0.1:0", CompatMode::V0_34).await; + println!("Creating client RPC WebSocket connection..."); + let url = server.node_addr.clone().try_into().unwrap(); + let (client, driver) = WebSocketClient::builder(url) + .compat_mode(CompatMode::V0_34) + .build() + .await + .unwrap(); + let driver_handle = tokio::spawn(async move { driver.run().await }); + + println!("Initiating subscription for new blocks..."); + let mut subs = client.subscribe(EventType::NewBlock.into()).await.unwrap(); + + // Collect all the events from the subscription. + let subs_collector_hdl = tokio::spawn(async move { + let mut results = Vec::new(); + while let Some(res) = subs.next().await { + results.push(res); + if results.len() == 3 { + break; + } } + results + }); + + println!("Publishing events"); + // Publish the events from this context + for ev in &test_events { + server.publish_event(ev.clone()).unwrap(); } - results - }); - println!("Publishing events"); - // Publish the events from this context - for ev in &test_events { - server.publish_event(ev.clone()).unwrap(); + println!("Collecting results from subscription..."); + let collected_results = subs_collector_hdl.await.unwrap(); + + client.close().unwrap(); + server.terminate().await.unwrap(); + let _ = driver_handle.await.unwrap(); + println!("Closed client and terminated server"); + + assert_eq!(3, collected_results.len()); + for i in 0..3 { + assert_eq!( + test_events[i], + collected_results[i].as_ref().unwrap().clone() + ); + } } + } - println!("Collecting results from subscription..."); - let collected_results = subs_collector_hdl.await.unwrap(); + mod v0_37 { + use super::*; + use crate::dialect::v0_37::Event as RpcEvent; - client.close().unwrap(); - server.terminate().await.unwrap(); - let _ = driver_handle.await.unwrap(); - println!("Closed client and terminated server"); + async fn read_event(name: &str) -> Event { + DialectEvent::::from_string(read_json_fixture("v0_37", name).await) + .unwrap() + .into() + } - assert_eq!(3, collected_results.len()); - for i in 0..3 { - assert_eq!( - test_events[i], - collected_results[i].as_ref().unwrap().clone() - ); + #[tokio::test] + async fn websocket_client_happy_path() { + let event1 = read_event("subscribe_newblock_0").await; + let event2 = read_event("subscribe_newblock_1").await; + let event3 = read_event("subscribe_newblock_2").await; + let test_events = vec![event1, event2, event3]; + + println!("Starting WebSocket server..."); + let mut server = TestServer::new("127.0.0.1:0", CompatMode::V0_37).await; + println!("Creating client RPC WebSocket connection..."); + let url = server.node_addr.clone().try_into().unwrap(); + let (client, driver) = WebSocketClient::builder(url) + .compat_mode(CompatMode::V0_37) + .build() + .await + .unwrap(); + let driver_handle = tokio::spawn(async move { driver.run().await }); + + println!("Initiating subscription for new blocks..."); + let mut subs = client.subscribe(EventType::NewBlock.into()).await.unwrap(); + + // Collect all the events from the subscription. + let subs_collector_hdl = tokio::spawn(async move { + let mut results = Vec::new(); + while let Some(res) = subs.next().await { + results.push(res); + if results.len() == 3 { + break; + } + } + results + }); + + println!("Publishing events"); + // Publish the events from this context + for ev in &test_events { + server.publish_event(ev.clone()).unwrap(); + } + + println!("Collecting results from subscription..."); + let collected_results = subs_collector_hdl.await.unwrap(); + + client.close().unwrap(); + server.terminate().await.unwrap(); + let _ = driver_handle.await.unwrap(); + println!("Closed client and terminated server"); + + assert_eq!(3, collected_results.len()); + for i in 0..3 { + assert_eq!( + test_events[i], + collected_results[i].as_ref().unwrap().clone() + ); + } } } diff --git a/rpc/src/dialect.rs b/rpc/src/dialect.rs new file mode 100644 index 000000000..ddcb94748 --- /dev/null +++ b/rpc/src/dialect.rs @@ -0,0 +1,32 @@ +//! Helper types to generalize differences in serialization between +//! Tendermint RPC protocol versions. + +pub mod v0_34; +pub mod v0_37; + +mod begin_block; +mod check_tx; +mod deliver_tx; +mod end_block; + +pub use begin_block::BeginBlock; +pub use check_tx::CheckTx; +pub use deliver_tx::DeliverTx; +pub use end_block::EndBlock; + +use serde::{de::DeserializeOwned, Serialize}; + +use tendermint::abci; + +pub trait Dialect: sealed::Sealed + Default + Clone + Send + Sync { + type Event: Into + Serialize + DeserializeOwned; +} + +pub type LatestDialect = v0_37::Dialect; + +mod sealed { + pub trait Sealed {} + + impl Sealed for super::v0_34::Dialect {} + impl Sealed for super::v0_37::Dialect {} +} diff --git a/rpc/src/dialect/begin_block.rs b/rpc/src/dialect/begin_block.rs new file mode 100644 index 000000000..fdb5a2a28 --- /dev/null +++ b/rpc/src/dialect/begin_block.rs @@ -0,0 +1,42 @@ +use serde::{Deserialize, Serialize}; + +use tendermint::abci; + +use crate::prelude::*; + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub struct BeginBlock { + /// Events that occurred while beginning the block. + #[serde(default = "Default::default")] + pub events: Vec, +} + +impl Default for BeginBlock { + fn default() -> Self { + Self { + events: Default::default(), + } + } +} + +impl From> for abci::response::BeginBlock +where + Ev: Into, +{ + fn from(msg: BeginBlock) -> Self { + Self { + events: msg.events.into_iter().map(Into::into).collect(), + } + } +} + +impl From for BeginBlock +where + abci::Event: Into, +{ + fn from(value: abci::response::BeginBlock) -> Self { + Self { + events: value.events.into_iter().map(Into::into).collect(), + } + } +} diff --git a/rpc/src/dialect/check_tx.rs b/rpc/src/dialect/check_tx.rs new file mode 100644 index 000000000..47b8d17c9 --- /dev/null +++ b/rpc/src/dialect/check_tx.rs @@ -0,0 +1,86 @@ +use bytes::Bytes; +use serde::{Deserialize, Serialize}; + +use tendermint::abci::{self, Code}; + +use crate::prelude::*; +use crate::serializers; + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +#[serde(default)] +pub struct CheckTx { + /// The response code. + /// + /// Transactions where `code != 0` will be rejected; these transactions will + /// not be broadcast to other nodes or included in a proposal block. + /// Tendermint attributes no other value to the response code. + pub code: Code, + /// Result bytes, if any. + #[serde(with = "serializers::nullable")] + pub data: Bytes, + /// The output of the application's logger. + /// + /// **May be non-deterministic**. + pub log: String, + /// Additional information. + /// + /// **May be non-deterministic**. + pub info: String, + /// Amount of gas requested for the transaction. + #[serde(with = "serializers::from_str")] + pub gas_wanted: i64, + /// Amount of gas consumed by the transaction. + #[serde(with = "serializers::from_str")] + pub gas_used: i64, + /// Events that occurred while checking the transaction. + pub events: Vec, + /// The namespace for the `code`. + pub codespace: String, + /// The transaction's sender (e.g. the signer). + pub sender: String, + /// The transaction's priority (for mempool ordering). + #[serde(with = "serializers::from_str")] + pub priority: i64, + /// mempool_error is set by Tendermint. + /// ABCI applictions should not set mempool_error. + pub mempool_error: String, +} + +impl Default for CheckTx { + fn default() -> Self { + Self { + code: Default::default(), + data: Default::default(), + log: Default::default(), + info: Default::default(), + gas_wanted: Default::default(), + gas_used: Default::default(), + events: Default::default(), + codespace: Default::default(), + sender: Default::default(), + priority: Default::default(), + mempool_error: Default::default(), + } + } +} + +impl From> for abci::response::CheckTx +where + Ev: Into, +{ + fn from(msg: CheckTx) -> Self { + Self { + code: msg.code, + data: msg.data, + log: msg.log, + info: msg.info, + gas_wanted: msg.gas_wanted, + gas_used: msg.gas_used, + events: msg.events.into_iter().map(Into::into).collect(), + codespace: msg.codespace, + sender: msg.sender, + priority: msg.priority, + mempool_error: msg.mempool_error, + } + } +} diff --git a/rpc/src/dialect/deliver_tx.rs b/rpc/src/dialect/deliver_tx.rs new file mode 100644 index 000000000..ccb0452ec --- /dev/null +++ b/rpc/src/dialect/deliver_tx.rs @@ -0,0 +1,72 @@ +use bytes::Bytes; +use serde::{Deserialize, Serialize}; + +use tendermint::abci::{self, Code}; + +use crate::prelude::*; +use crate::serializers; + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +#[serde(default)] +pub struct DeliverTx { + /// The response code. + /// + /// This code should be `0` only if the transaction is fully valid. However, + /// invalid transactions included in a block will still be executed against + /// the application state. + pub code: Code, + /// Result bytes, if any. + #[serde(with = "serializers::nullable")] + pub data: Bytes, + /// The output of the application's logger. + /// + /// **May be non-deterministic**. + pub log: String, + /// Additional information. + /// + /// **May be non-deterministic**. + pub info: String, + /// Amount of gas requested for the transaction. + #[serde(with = "serializers::from_str")] + pub gas_wanted: i64, + /// Amount of gas consumed by the transaction. + #[serde(with = "serializers::from_str")] + pub gas_used: i64, + /// Events that occurred while executing the transaction. + pub events: Vec, + /// The namespace for the `code`. + pub codespace: String, +} + +impl Default for DeliverTx { + fn default() -> Self { + Self { + code: Default::default(), + data: Default::default(), + log: Default::default(), + info: Default::default(), + gas_wanted: Default::default(), + gas_used: Default::default(), + events: Default::default(), + codespace: Default::default(), + } + } +} + +impl From> for abci::response::DeliverTx +where + Ev: Into, +{ + fn from(msg: DeliverTx) -> Self { + Self { + code: msg.code, + data: msg.data, + log: msg.log, + info: msg.info, + gas_wanted: msg.gas_wanted, + gas_used: msg.gas_used, + events: msg.events.into_iter().map(Into::into).collect(), + codespace: msg.codespace, + } + } +} diff --git a/rpc/src/dialect/end_block.rs b/rpc/src/dialect/end_block.rs new file mode 100644 index 000000000..89f556a1e --- /dev/null +++ b/rpc/src/dialect/end_block.rs @@ -0,0 +1,56 @@ +use serde::{Deserialize, Serialize}; + +use tendermint::{abci, consensus, validator}; + +use crate::prelude::*; +use crate::serializers; + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub struct EndBlock { + /// Changes to the validator set, if any. + /// + /// Setting the voting power to 0 removes a validator. + #[serde(with = "serializers::nullable")] + pub validator_updates: Vec, + /// Changes to consensus parameters (optional). + pub consensus_param_updates: Option, + /// Events that occurred while ending the block. + #[serde(default = "Default::default")] + pub events: Vec, +} + +impl Default for EndBlock { + fn default() -> Self { + Self { + validator_updates: Default::default(), + consensus_param_updates: Default::default(), + events: Default::default(), + } + } +} + +impl From> for abci::response::EndBlock +where + Ev: Into, +{ + fn from(msg: EndBlock) -> Self { + Self { + events: msg.events.into_iter().map(Into::into).collect(), + validator_updates: msg.validator_updates, + consensus_param_updates: msg.consensus_param_updates, + } + } +} + +impl From for EndBlock +where + abci::Event: Into, +{ + fn from(value: abci::response::EndBlock) -> Self { + Self { + events: value.events.into_iter().map(Into::into).collect(), + validator_updates: value.validator_updates, + consensus_param_updates: value.consensus_param_updates, + } + } +} diff --git a/rpc/src/dialect/v0_34.rs b/rpc/src/dialect/v0_34.rs new file mode 100644 index 000000000..6e972b1d7 --- /dev/null +++ b/rpc/src/dialect/v0_34.rs @@ -0,0 +1,77 @@ +use tendermint::abci; + +use crate::prelude::*; +use crate::serializers::bytes::base64string; +use serde::{Deserialize, Serialize}; + +#[derive(Default, Clone)] +pub struct Dialect; + +impl crate::dialect::Dialect for Dialect { + type Event = Event; +} + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub struct Event { + #[serde(rename = "type")] + pub kind: String, + pub attributes: Vec, +} + +impl From for abci::Event { + fn from(msg: Event) -> Self { + Self { + kind: msg.kind, + attributes: msg.attributes.into_iter().map(Into::into).collect(), + } + } +} + +impl From for Event { + fn from(msg: abci::Event) -> Self { + Self { + kind: msg.kind, + attributes: msg.attributes.into_iter().map(Into::into).collect(), + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub struct EventAttribute { + /// The event key. + #[serde( + serialize_with = "base64string::serialize", + deserialize_with = "base64string::deserialize_to_string" + )] + pub key: String, + /// The event value. + #[serde( + serialize_with = "base64string::serialize", + deserialize_with = "base64string::deserialize_to_string" + )] + pub value: String, + /// Whether Tendermint's indexer should index this event. + /// + /// **This field is nondeterministic**. + pub index: bool, +} + +impl From for abci::EventAttribute { + fn from(msg: EventAttribute) -> Self { + Self { + key: msg.key, + value: msg.value, + index: msg.index, + } + } +} + +impl From for EventAttribute { + fn from(msg: abci::EventAttribute) -> Self { + Self { + key: msg.key, + value: msg.value, + index: msg.index, + } + } +} diff --git a/rpc/src/dialect/v0_37.rs b/rpc/src/dialect/v0_37.rs new file mode 100644 index 000000000..28cc49947 --- /dev/null +++ b/rpc/src/dialect/v0_37.rs @@ -0,0 +1,68 @@ +use tendermint::abci; + +use crate::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Default, Clone)] +pub struct Dialect; + +impl crate::dialect::Dialect for Dialect { + type Event = Event; +} + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub struct Event { + #[serde(rename = "type")] + pub kind: String, + pub attributes: Vec, +} + +impl From for abci::Event { + fn from(msg: Event) -> Self { + Self { + kind: msg.kind, + attributes: msg.attributes.into_iter().map(Into::into).collect(), + } + } +} + +impl From for Event { + fn from(msg: abci::Event) -> Self { + Self { + kind: msg.kind, + attributes: msg.attributes.into_iter().map(Into::into).collect(), + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub struct EventAttribute { + /// The event key. + pub key: String, + /// The event value. + pub value: String, + /// Whether Tendermint's indexer should index this event. + /// + /// **This field is nondeterministic**. + pub index: bool, +} + +impl From for abci::EventAttribute { + fn from(msg: EventAttribute) -> Self { + Self { + key: msg.key, + value: msg.value, + index: msg.index, + } + } +} + +impl From for EventAttribute { + fn from(msg: abci::EventAttribute) -> Self { + Self { + key: msg.key, + value: msg.value, + index: msg.index, + } + } +} diff --git a/rpc/src/endpoint.rs b/rpc/src/endpoint.rs index 2e749aaa6..f04c2a0df 100644 --- a/rpc/src/endpoint.rs +++ b/rpc/src/endpoint.rs @@ -13,6 +13,8 @@ pub mod consensus_params; pub mod consensus_state; pub mod evidence; pub mod genesis; +pub mod header; +pub mod header_by_hash; pub mod health; pub mod net_info; pub mod status; diff --git a/rpc/src/endpoint/abci_info.rs b/rpc/src/endpoint/abci_info.rs index 318207138..1d174aa18 100644 --- a/rpc/src/endpoint/abci_info.rs +++ b/rpc/src/endpoint/abci_info.rs @@ -2,19 +2,26 @@ use serde::{Deserialize, Serialize}; +use crate::dialect::Dialect; +use crate::request::RequestMessage; + /// Request ABCI information from a node #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Request; -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::AbciInfo } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// ABCI information response #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/abci_query.rs b/rpc/src/endpoint/abci_query.rs index 7ed6cc464..4a025cf23 100644 --- a/rpc/src/endpoint/abci_query.rs +++ b/rpc/src/endpoint/abci_query.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use tendermint::{abci::Code, block, merkle::proof::ProofOps, serializers}; use crate::prelude::*; +use crate::{dialect::Dialect, request::RequestMessage}; /// Query the ABCI application for information #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -40,15 +41,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::AbciQuery } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// ABCI query response wrapper #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/block.rs b/rpc/src/endpoint/block.rs index a321d58a8..558f7dc0e 100644 --- a/rpc/src/endpoint/block.rs +++ b/rpc/src/endpoint/block.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; use tendermint::block::{self, Block}; +use crate::{dialect::Dialect, request::RequestMessage}; + /// Get information about a specific block #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] pub struct Request { @@ -21,15 +23,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::Block } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Block responses #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/block_by_hash.rs b/rpc/src/endpoint/block_by_hash.rs index 09100fce6..84a16e212 100644 --- a/rpc/src/endpoint/block_by_hash.rs +++ b/rpc/src/endpoint/block_by_hash.rs @@ -6,6 +6,8 @@ use tendermint::{ Hash, }; +use crate::{dialect::Dialect, request::RequestMessage}; + /// Get information about a specific block by its hash #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] pub struct Request { @@ -30,15 +32,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::BlockByHash } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Block responses #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/block_results.rs b/rpc/src/endpoint/block_results.rs index 75f5de739..ee28cb03b 100644 --- a/rpc/src/endpoint/block_results.rs +++ b/rpc/src/endpoint/block_results.rs @@ -1,9 +1,12 @@ //! `/block_results` endpoint JSON-RPC wrapper +use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use tendermint::{abci, block, consensus, validator}; +use crate::dialect::{self, Dialect}; use crate::prelude::*; +use crate::request::RequestMessage; use crate::serializers; /// Get ABCI results at a given height. @@ -24,18 +27,22 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::BlockResults } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = DialectResponse; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// ABCI result response. -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Serialize)] pub struct Response { /// Block height pub height: block::Height, @@ -49,6 +56,28 @@ pub struct Response { /// End block events (might be explicit null) pub end_block_events: Option>, + /// Validator updates (might be explicit null) + pub validator_updates: Vec, + + /// New consensus params (might be explicit null) + pub consensus_param_updates: Option, +} + +/// RPC dialect helper for serialization of the response. +#[derive(Debug, Serialize, Deserialize)] +pub struct DialectResponse { + /// Block height + pub height: block::Height, + + /// Txs results (might be explicit null) + pub txs_results: Option>>, + + /// Begin block events (might be explicit null) + pub begin_block_events: Option>, + + /// End block events (might be explicit null) + pub end_block_events: Option>, + /// Validator updates (might be explicit null) #[serde(deserialize_with = "serializers::nullable::deserialize")] pub validator_updates: Vec, @@ -57,4 +86,26 @@ pub struct Response { pub consensus_param_updates: Option, } -impl crate::Response for Response {} +impl crate::Response for DialectResponse where Ev: Serialize + DeserializeOwned {} + +impl From> for Response +where + Ev: Into, +{ + fn from(msg: DialectResponse) -> Self { + Response { + height: msg.height, + txs_results: msg + .txs_results + .map(|v| v.into_iter().map(Into::into).collect()), + begin_block_events: msg + .begin_block_events + .map(|v| v.into_iter().map(Into::into).collect()), + end_block_events: msg + .end_block_events + .map(|v| v.into_iter().map(Into::into).collect()), + validator_updates: msg.validator_updates, + consensus_param_updates: msg.consensus_param_updates, + } + } +} diff --git a/rpc/src/endpoint/block_search.rs b/rpc/src/endpoint/block_search.rs index dad8d8add..2cfc92f0f 100644 --- a/rpc/src/endpoint/block_search.rs +++ b/rpc/src/endpoint/block_search.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; pub use super::{block, block_results}; -use crate::{prelude::*, serializers, Method, Order}; +use crate::{dialect::Dialect, prelude::*, request::RequestMessage, serializers, Method, Order}; /// Request for searching for blocks by their BeginBlock and EndBlock events. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -28,15 +28,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> Method { Method::BlockSearch } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Response { diff --git a/rpc/src/endpoint/blockchain.rs b/rpc/src/endpoint/blockchain.rs index 5fb8ecf24..76883ab15 100644 --- a/rpc/src/endpoint/blockchain.rs +++ b/rpc/src/endpoint/blockchain.rs @@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize}; use tendermint::block; use crate::prelude::*; +use crate::{dialect::Dialect, request::RequestMessage}; /// Get information about a specific block #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -35,15 +36,19 @@ impl From> for Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::Blockchain } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Block responses #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/broadcast/tx_async.rs b/rpc/src/endpoint/broadcast/tx_async.rs index 278f2b7be..3880d3e24 100644 --- a/rpc/src/endpoint/broadcast/tx_async.rs +++ b/rpc/src/endpoint/broadcast/tx_async.rs @@ -4,7 +4,7 @@ use bytes::Bytes; use serde::{Deserialize, Serialize}; use tendermint::{abci::Code, Hash}; -use crate::{prelude::*, serializers}; +use crate::{dialect::Dialect, prelude::*, request::RequestMessage, serializers}; /// `/broadcast_tx_async`: broadcast a transaction and return immediately. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -21,15 +21,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::BroadcastTxAsync } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Response from either an async or sync transaction broadcast request. #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/broadcast/tx_commit.rs b/rpc/src/endpoint/broadcast/tx_commit.rs index 37a4b1448..195f04295 100644 --- a/rpc/src/endpoint/broadcast/tx_commit.rs +++ b/rpc/src/endpoint/broadcast/tx_commit.rs @@ -1,10 +1,13 @@ //! `/broadcast_tx_commit`: only returns error if `mempool.CheckTx()` errs or //! if we timeout waiting for tx to commit. +use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; + use tendermint::{abci, block, Hash}; -use crate::{prelude::*, serializers}; +use crate::dialect::{self, Dialect}; +use crate::{prelude::*, request::RequestMessage, serializers}; /// `/broadcast_tx_commit`: only returns error if `mempool.CheckTx()` errs or /// if we timeout waiting for tx to commit. @@ -25,18 +28,22 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::BroadcastTxCommit } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = DialectResponse; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Response from `/broadcast_tx_commit`. -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Serialize)] pub struct Response { /// `CheckTx` result pub check_tx: abci::response::CheckTx, @@ -51,4 +58,34 @@ pub struct Response { pub height: block::Height, } -impl crate::Response for Response {} +/// RPC dialect helper for serialization of the response. +#[derive(Debug, Deserialize, Serialize)] +pub struct DialectResponse { + /// `CheckTx` result + pub check_tx: dialect::CheckTx, + + /// `DeliverTx` result + pub deliver_tx: dialect::DeliverTx, + + /// Transaction + pub hash: Hash, + + /// Height + pub height: block::Height, +} + +impl crate::Response for DialectResponse where Ev: Serialize + DeserializeOwned {} + +impl From> for Response +where + Ev: Into, +{ + fn from(msg: DialectResponse) -> Self { + Self { + check_tx: msg.check_tx.into(), + deliver_tx: msg.deliver_tx.into(), + hash: msg.hash, + height: msg.height, + } + } +} diff --git a/rpc/src/endpoint/broadcast/tx_sync.rs b/rpc/src/endpoint/broadcast/tx_sync.rs index ef6a709c1..8bd0a6295 100644 --- a/rpc/src/endpoint/broadcast/tx_sync.rs +++ b/rpc/src/endpoint/broadcast/tx_sync.rs @@ -4,7 +4,7 @@ use bytes::Bytes; use serde::{Deserialize, Serialize}; use tendermint::{abci::Code, Hash}; -use crate::{prelude::*, serializers}; +use crate::{dialect::Dialect, prelude::*, request::RequestMessage, serializers}; /// `/broadcast_tx_sync`: returns with the response from `CheckTx`. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -21,15 +21,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::BroadcastTxSync } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Response from either an async or sync transaction broadcast request. #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/commit.rs b/rpc/src/endpoint/commit.rs index f21e69cc6..b65635fd2 100644 --- a/rpc/src/endpoint/commit.rs +++ b/rpc/src/endpoint/commit.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; use tendermint::{block, block::signed_header::SignedHeader}; +use crate::{dialect::Dialect, request::RequestMessage}; + /// Get commit information about a specific block #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] pub struct Request { @@ -18,15 +20,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::Commit } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Commit responses #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/consensus_params.rs b/rpc/src/endpoint/consensus_params.rs index bb45cff2a..5f20b2b80 100644 --- a/rpc/src/endpoint/consensus_params.rs +++ b/rpc/src/endpoint/consensus_params.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; use tendermint::block::Height; +use crate::{dialect::Dialect, request::RequestMessage}; + /// Get the consensus parameters. /// /// If no height is supplied, the latest consensus parameters will be returned. @@ -20,15 +22,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::ConsensusParams } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Consensus parameters response. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] diff --git a/rpc/src/endpoint/consensus_state.rs b/rpc/src/endpoint/consensus_state.rs index 0a0d011c6..0186e69a0 100644 --- a/rpc/src/endpoint/consensus_state.rs +++ b/rpc/src/endpoint/consensus_state.rs @@ -10,7 +10,7 @@ use tendermint::{ hash, vote, Hash, Time, }; -use crate::{prelude::*, Error, Method}; +use crate::{dialect::Dialect, prelude::*, request::RequestMessage, Error, Method}; // From const NIL_VOTE_STR: &str = "nil-Vote"; @@ -25,15 +25,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> Method { Method::ConsensusState } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// The current consensus state (UNSTABLE). /// diff --git a/rpc/src/endpoint/evidence.rs b/rpc/src/endpoint/evidence.rs index f5d4d4255..d45977174 100644 --- a/rpc/src/endpoint/evidence.rs +++ b/rpc/src/endpoint/evidence.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use tendermint::{evidence::Evidence, Hash}; -use crate::Method; +use crate::{dialect::Dialect, request::RequestMessage, Method}; /// `/broadcast_evidence`: broadcast an evidence. #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] @@ -19,15 +19,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> Method { Method::BroadcastEvidence } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Response from either an evidence broadcast request. #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/genesis.rs b/rpc/src/endpoint/genesis.rs index 9893bfb36..698fb3ddd 100644 --- a/rpc/src/endpoint/genesis.rs +++ b/rpc/src/endpoint/genesis.rs @@ -5,6 +5,8 @@ use core::{fmt, marker::PhantomData}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use tendermint::Genesis; +use crate::{dialect::Dialect, request::RequestMessage}; + /// Get the genesis state for the current chain #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Request(#[serde(skip)] PhantomData); @@ -15,20 +17,29 @@ impl Default for Request { } } -impl crate::Request for Request +impl RequestMessage for Request where - AppState: fmt::Debug + Serialize + DeserializeOwned + Send, + AppState: Serialize + DeserializeOwned, { - type Response = Response; - fn method(&self) -> crate::Method { crate::Method::Genesis } } -impl crate::SimpleRequest for Request where - AppState: fmt::Debug + Serialize + DeserializeOwned + Send +impl crate::Request for Request +where + AppState: fmt::Debug + Serialize + DeserializeOwned + Send, + S: Dialect, +{ + type Response = Response; +} + +impl crate::SimpleRequest for Request +where + AppState: fmt::Debug + Serialize + DeserializeOwned + Send, + S: Dialect, { + type Output = Response; } /// Block responses diff --git a/rpc/src/endpoint/header.rs b/rpc/src/endpoint/header.rs new file mode 100644 index 000000000..ad1506205 --- /dev/null +++ b/rpc/src/endpoint/header.rs @@ -0,0 +1,56 @@ +//! `/header` endpoint JSON-RPC wrapper + +use serde::{Deserialize, Serialize}; +use tendermint::block::{self, Header}; + +use crate::dialect::v0_37; +use crate::request::RequestMessage; + +/// Get information about a specific block +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub struct Request { + /// Height of the block header to request. + /// + /// If no height is provided, it will fetch results for the latest block. + pub height: Option, +} + +impl Request { + /// Create a new request for header information about a particular block + pub fn new(height: block::Height) -> Self { + Self { + height: Some(height), + } + } +} + +impl RequestMessage for Request { + fn method(&self) -> crate::Method { + crate::Method::Header + } +} + +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} + +/// Header response +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Response { + /// Header data + pub header: Header, +} + +impl crate::Response for Response {} + +impl From for Response { + fn from(block_resp: super::block::Response) -> Self { + Response { + header: block_resp.block.header, + } + } +} diff --git a/rpc/src/endpoint/header_by_hash.rs b/rpc/src/endpoint/header_by_hash.rs new file mode 100644 index 000000000..e887944e2 --- /dev/null +++ b/rpc/src/endpoint/header_by_hash.rs @@ -0,0 +1,62 @@ +//! `/header_by_hash` endpoint JSON-RPC wrapper + +use serde::{Deserialize, Serialize}; +use tendermint::{block::Header, Hash}; + +use crate::dialect::v0_37; +use crate::request::RequestMessage; + +/// Get information about a specific block by its hash +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub struct Request { + /// Hash of the block to request. + /// + /// If no hash is provided, it will return no header (as if the hash + /// did not match any block). + /// + /// Serialized internally into a hex-encoded string before sending to + /// the RPC server. + #[serde(default)] + #[serde(with = "crate::serializers::option_hash")] + pub hash: Option, +} + +impl Request { + /// Create a new request for information about a particular block + pub fn new>(hash: H) -> Self { + Self { + hash: Some(hash.into()), + } + } +} + +impl RequestMessage for Request { + fn method(&self) -> crate::Method { + crate::Method::HeaderByHash + } +} + +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} + +/// Header response +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Response { + /// Header data + pub header: Option
, +} + +impl crate::Response for Response {} + +impl From for Response { + fn from(block_resp: super::block_by_hash::Response) -> Self { + Response { + header: block_resp.block.map(|b| b.header), + } + } +} diff --git a/rpc/src/endpoint/health.rs b/rpc/src/endpoint/health.rs index 677dee9e1..7699cf0d0 100644 --- a/rpc/src/endpoint/health.rs +++ b/rpc/src/endpoint/health.rs @@ -2,19 +2,25 @@ use serde::{Deserialize, Serialize}; +use crate::{dialect::Dialect, request::RequestMessage}; + /// Perform a basic healthceck of the backend #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Request; -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::Health } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Healthcheck responses #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/net_info.rs b/rpc/src/endpoint/net_info.rs index da2b56920..f7f4fe6ca 100644 --- a/rpc/src/endpoint/net_info.rs +++ b/rpc/src/endpoint/net_info.rs @@ -10,20 +10,25 @@ use serde::{Deserialize, Serialize}; use tendermint::{channel::Channel, node, serializers, Time}; use crate::prelude::*; +use crate::{dialect::Dialect, request::RequestMessage}; /// Request network information from a node #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Request; -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::NetInfo } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Net info responses #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/status.rs b/rpc/src/endpoint/status.rs index 434b6185d..2850eec13 100644 --- a/rpc/src/endpoint/status.rs +++ b/rpc/src/endpoint/status.rs @@ -3,19 +3,25 @@ use serde::{Deserialize, Serialize}; use tendermint::{block, node, validator, AppHash, Hash, Time}; +use crate::{dialect::Dialect, request::RequestMessage}; + /// Node status request #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Request; -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::Status } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Status responses #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/endpoint/subscribe.rs b/rpc/src/endpoint/subscribe.rs index 2874bf8b7..df99dc6d7 100644 --- a/rpc/src/endpoint/subscribe.rs +++ b/rpc/src/endpoint/subscribe.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::prelude::*; +use crate::{dialect::Dialect, request::RequestMessage}; /// Subscription request for events. /// @@ -23,14 +24,16 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::Subscribe } } +impl crate::Request for Request { + type Response = Response; +} + /// Status responses #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Response {} diff --git a/rpc/src/endpoint/tx.rs b/rpc/src/endpoint/tx.rs index fed4ae85b..dcf6fad9d 100644 --- a/rpc/src/endpoint/tx.rs +++ b/rpc/src/endpoint/tx.rs @@ -1,9 +1,11 @@ //! `/tx` endpoint JSON-RPC wrapper +use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use tendermint::{abci, block, tx, Hash}; -use crate::{prelude::*, serializers, Method}; +use crate::dialect::{DeliverTx, Dialect}; +use crate::{prelude::*, request::RequestMessage, serializers, Method}; /// Request for finding a transaction by its hash. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -26,17 +28,21 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> Method { Method::Tx } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = DialectResponse; +} -#[derive(Clone, Debug, Deserialize, Serialize)] +impl crate::SimpleRequest for Request { + type Output = Response; +} + +#[derive(Clone, Debug, Serialize)] pub struct Response { /// The hash of the transaction. /// @@ -47,10 +53,42 @@ pub struct Response { pub height: block::Height, pub index: u32, pub tx_result: abci::response::DeliverTx, + pub tx: Vec, + pub proof: Option, +} + +/// RPC dialect helper for serialization of the response. +#[derive(Debug, Deserialize, Serialize)] +pub struct DialectResponse { + /// The hash of the transaction. + /// + /// Deserialized from a hex-encoded string (there is a discrepancy between + /// the format used for the request and the format used for the response in + /// the Tendermint RPC). + pub hash: Hash, + pub height: block::Height, + pub index: u32, + pub tx_result: DeliverTx, #[serde(with = "serializers::bytes::base64string")] pub tx: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub proof: Option, } -impl crate::Response for Response {} +impl crate::Response for DialectResponse where Ev: Serialize + DeserializeOwned {} + +impl From> for Response +where + Ev: Into, +{ + fn from(msg: DialectResponse) -> Self { + Self { + hash: msg.hash, + height: msg.height, + index: msg.index, + tx_result: msg.tx_result.into(), + tx: msg.tx, + proof: msg.proof, + } + } +} diff --git a/rpc/src/endpoint/tx_search.rs b/rpc/src/endpoint/tx_search.rs index b59ca2475..278a66c79 100644 --- a/rpc/src/endpoint/tx_search.rs +++ b/rpc/src/endpoint/tx_search.rs @@ -1,9 +1,11 @@ //! `/tx_search` endpoint JSON-RPC wrapper -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +use tendermint::abci; pub use super::tx; -use crate::{prelude::*, serializers, Method, Order}; +use crate::{dialect::Dialect, prelude::*, request::RequestMessage, serializers, Method, Order}; /// Request for searching for transactions with their results. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -36,21 +38,44 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> Method { Method::TxSearch } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = DialectResponse; +} -#[derive(Clone, Debug, Deserialize, Serialize)] +impl crate::SimpleRequest for Request { + type Output = Response; +} + +#[derive(Clone, Debug, Serialize)] pub struct Response { pub txs: Vec, + pub total_count: u32, +} + +/// RPC dialect helper for serialization of the response. +#[derive(Debug, Deserialize, Serialize)] +pub struct DialectResponse { + pub txs: Vec>, #[serde(with = "serializers::from_str")] pub total_count: u32, } -impl crate::Response for Response {} +impl crate::Response for DialectResponse where Ev: Serialize + DeserializeOwned {} + +impl From> for Response +where + Ev: Into, +{ + fn from(msg: DialectResponse) -> Self { + Self { + txs: msg.txs.into_iter().map(Into::into).collect(), + total_count: msg.total_count, + } + } +} diff --git a/rpc/src/endpoint/unsubscribe.rs b/rpc/src/endpoint/unsubscribe.rs index b1c4596fc..37faf94d1 100644 --- a/rpc/src/endpoint/unsubscribe.rs +++ b/rpc/src/endpoint/unsubscribe.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::prelude::*; +use crate::{dialect::Dialect, request::RequestMessage}; /// Request to unsubscribe from events relating to a given query. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -17,14 +18,16 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::Unsubscribe } } +impl crate::Request for Request { + type Response = Response; +} + /// Status responses #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Response {} diff --git a/rpc/src/endpoint/validators.rs b/rpc/src/endpoint/validators.rs index d71cf915d..c4bded01d 100644 --- a/rpc/src/endpoint/validators.rs +++ b/rpc/src/endpoint/validators.rs @@ -3,7 +3,9 @@ use serde::{Deserialize, Serialize}; use tendermint::{block, validator}; -use crate::{prelude::*, serializers, PageNumber, PerPage}; +use crate::{ + dialect::Dialect, prelude::*, request::RequestMessage, serializers, PageNumber, PerPage, +}; /// The default number of validators to return per page. pub const DEFAULT_VALIDATORS_PER_PAGE: u8 = 30; @@ -43,15 +45,19 @@ impl Request { } } -impl crate::Request for Request { - type Response = Response; - +impl RequestMessage for Request { fn method(&self) -> crate::Method { crate::Method::Validators } } -impl crate::SimpleRequest for Request {} +impl crate::Request for Request { + type Response = Response; +} + +impl crate::SimpleRequest for Request { + type Output = Response; +} /// Validator responses #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/rpc/src/error.rs b/rpc/src/error.rs index 3c9ff4435..c1119708b 100644 --- a/rpc/src/error.rs +++ b/rpc/src/error.rs @@ -203,6 +203,21 @@ define_error! { e.version, e.supported) }, + InvalidTendermintVersion + { + version: String, + } + | e | { + format_args!("invalid Tendermint version reported by the node: {}", e.version) + }, + + UnsupportedTendermintVersion + { + version: String, + } + | e | { + format_args!("unsupported Tendermint version reported by the node: {}", e.version) + }, } } diff --git a/rpc/src/event.rs b/rpc/src/event.rs index 5ce997796..6133c8845 100644 --- a/rpc/src/event.rs +++ b/rpc/src/event.rs @@ -2,15 +2,15 @@ use alloc::collections::BTreeMap as HashMap; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use tendermint::{abci, Block}; -use crate::{prelude::*, query::EventType, response::Wrapper, serializers, Response}; +use crate::{dialect, prelude::*, query::EventType, response::Wrapper, serializers, Response}; /// An incoming event produced by a [`Subscription`]. /// /// [`Subscription`]: ../struct.Subscription.html -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Event { /// The query that produced the event. pub query: String, @@ -19,10 +19,23 @@ pub struct Event { /// Event type and attributes map. pub events: Option>>, } -impl Response for Event {} + +// Serialization helper supporting differences in RPC versions. +#[derive(Serialize, Deserialize, Debug)] +pub struct DialectEvent { + /// The query that produced the event. + pub query: String, + /// The data associated with the event. + pub data: DialectEventData, + /// Event type and attributes map. + pub events: Option>>, +} + +impl Response for DialectEvent where Ev: Serialize + DeserializeOwned {} /// A JSON-RPC-wrapped event. -pub type WrappedEvent = Wrapper; +#[allow(dead_code)] +pub(crate) type WrappedEvent = Wrapper>; impl Event { /// Returns the type associated with this event, if we recognize it. @@ -37,41 +50,199 @@ impl Event { } } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] -#[serde(tag = "type", content = "value")] +impl From> for Event +where + Ev: Into, +{ + fn from(msg: DialectEvent) -> Self { + Event { + query: msg.query, + data: msg.data.into(), + events: msg.events, + } + } +} + +impl From for DialectEvent +where + abci::Event: Into, +{ + fn from(msg: Event) -> Self { + DialectEvent { + query: msg.query, + data: msg.data.into(), + events: msg.events, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] // To be fixed in 0.24 #[allow(clippy::large_enum_variant)] pub enum EventData { - #[serde(alias = "tendermint/event/NewBlock")] NewBlock { block: Option, result_begin_block: Option, result_end_block: Option, }, + Tx { + tx_result: TxInfo, + }, + GenericJsonEvent(serde_json::Value), +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "type", content = "value")] +#[allow(clippy::large_enum_variant)] +pub enum DialectEventData { + #[serde(alias = "tendermint/event/NewBlock")] + NewBlock { + block: Option, + result_begin_block: Option>, + result_end_block: Option>, + }, #[serde(alias = "tendermint/event/Tx")] Tx { #[serde(rename = "TxResult")] - tx_result: TxInfo, + tx_result: DialectTxInfo, }, GenericJsonEvent(serde_json::Value), } +impl From> for EventData +where + Ev: Into, +{ + fn from(msg: DialectEventData) -> Self { + match msg { + DialectEventData::NewBlock { + block, + result_begin_block, + result_end_block, + } => EventData::NewBlock { + block, + result_begin_block: result_begin_block.map(Into::into), + result_end_block: result_end_block.map(Into::into), + }, + DialectEventData::Tx { tx_result } => EventData::Tx { + tx_result: tx_result.into(), + }, + DialectEventData::GenericJsonEvent(v) => EventData::GenericJsonEvent(v), + } + } +} + +impl From for DialectEventData +where + abci::Event: Into, +{ + fn from(msg: EventData) -> Self { + match msg { + EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } => DialectEventData::NewBlock { + block, + result_begin_block: result_begin_block.map(Into::into), + result_end_block: result_end_block.map(Into::into), + }, + EventData::Tx { tx_result } => DialectEventData::Tx { + tx_result: tx_result.into(), + }, + EventData::GenericJsonEvent(v) => DialectEventData::GenericJsonEvent(v), + } + } +} + /// Transaction result info. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct TxInfo { + pub height: i64, + pub index: Option, + pub tx: Vec, + pub result: TxResult, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct DialectTxInfo { #[serde(with = "serializers::from_str")] pub height: i64, pub index: Option, #[serde(with = "serializers::bytes::base64string")] pub tx: Vec, - pub result: TxResult, + pub result: DialectTxResult, +} + +impl From> for TxInfo +where + Ev: Into, +{ + fn from(msg: DialectTxInfo) -> Self { + TxInfo { + height: msg.height, + index: msg.index, + tx: msg.tx, + result: msg.result.into(), + } + } +} + +impl From for DialectTxInfo +where + abci::Event: Into, +{ + fn from(msg: TxInfo) -> Self { + DialectTxInfo { + height: msg.height, + index: msg.index, + tx: msg.tx, + result: msg.result.into(), + } + } } /// Transaction result. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct TxResult { pub log: Option, pub gas_wanted: Option, pub gas_used: Option, pub events: Vec, } + +#[derive(Serialize, Deserialize, Debug)] +pub struct DialectTxResult { + pub log: Option, + pub gas_wanted: Option, + pub gas_used: Option, + pub events: Vec, +} + +impl From> for TxResult +where + Ev: Into, +{ + fn from(msg: DialectTxResult) -> Self { + TxResult { + log: msg.log, + gas_wanted: msg.gas_wanted, + gas_used: msg.gas_used, + events: msg.events.into_iter().map(Into::into).collect(), + } + } +} + +impl From for DialectTxResult +where + abci::Event: Into, +{ + fn from(msg: TxResult) -> Self { + DialectTxResult { + log: msg.log, + gas_wanted: msg.gas_wanted, + gas_used: msg.gas_used, + events: msg.events.into_iter().map(Into::into).collect(), + } + } +} diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 4b9e6f1a3..9fba54790 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -33,7 +33,7 @@ extern crate std; mod prelude; #[cfg(any(feature = "http-client", feature = "websocket-client"))] -mod client; +pub mod client; #[cfg(any(feature = "http-client", feature = "websocket-client"))] pub use client::{ Client, MockClient, MockRequestMatcher, MockRequestMethodMatcher, Subscription, @@ -44,6 +44,7 @@ pub use client::{HttpClient, HttpClientUrl}; #[cfg(feature = "websocket-client")] pub use client::{WebSocketClient, WebSocketClientDriver, WebSocketClientUrl, WebSocketConfig}; +pub mod dialect; pub mod endpoint; pub mod error; pub mod event; diff --git a/rpc/src/method.rs b/rpc/src/method.rs index 1432b269c..6f91c5d5f 100644 --- a/rpc/src/method.rs +++ b/rpc/src/method.rs @@ -56,6 +56,12 @@ pub enum Method { /// Get genesis file Genesis, + /// Get block header + Header, + + /// Get block header by hash + HeaderByHash, + /// Get health info Health, @@ -103,6 +109,8 @@ impl Method { Method::ConsensusParams => "consensus_params", Method::ConsensusState => "consensus_state", Method::Genesis => "genesis", + Method::Header => "header", + Method::HeaderByHash => "header_by_hash", Method::Health => "health", Method::NetInfo => "net_info", Method::Status => "status", @@ -125,6 +133,8 @@ impl FromStr for Method { "block" => Method::Block, "block_by_hash" => Method::BlockByHash, "block_results" => Method::BlockResults, + "header" => Method::Header, + "header_by_hash" => Method::HeaderByHash, "block_search" => Method::BlockSearch, "blockchain" => Method::Blockchain, "broadcast_evidence" => Method::BroadcastEvidence, diff --git a/rpc/src/request.rs b/rpc/src/request.rs index ccafc45a3..684746479 100644 --- a/rpc/src/request.rs +++ b/rpc/src/request.rs @@ -5,13 +5,11 @@ use core::fmt::Debug; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use super::{Id, Method, Version}; +use crate::dialect::{Dialect, LatestDialect}; use crate::{prelude::*, Error}; -/// JSON-RPC requests -pub trait Request: Debug + DeserializeOwned + Serialize + Sized + Send { - /// Response type for this command - type Response: super::response::Response; - +/// Serialization for JSON-RPC requests +pub trait RequestMessage: DeserializeOwned + Serialize + Sized { /// Request method fn method(&self) -> Method; @@ -27,6 +25,12 @@ pub trait Request: Debug + DeserializeOwned + Serialize + Sized + Send { } } +/// JSON-RPC requests +pub trait Request: RequestMessage + Send { + /// Response type for this command + type Response: super::response::Response; +} + /// Simple JSON-RPC requests which correlate with a single response from the /// remote endpoint. /// @@ -35,7 +39,10 @@ pub trait Request: Debug + DeserializeOwned + Serialize + Sized + Send { /// simple, singular response. /// /// [`Subscription`]: struct.Subscription.html -pub trait SimpleRequest: Request {} +pub trait SimpleRequest: Request { + /// The output data, converted from Response. + type Output: From; +} /// JSON-RPC request wrapper (i.e. message envelope) #[derive(Debug, Deserialize, Serialize)] @@ -55,7 +62,7 @@ pub struct Wrapper { impl Wrapper where - R: Request, + R: RequestMessage, { /// Create a new request wrapper from the given request. /// diff --git a/rpc/tests/gaia_fixtures.rs b/rpc/tests/gaia_fixtures.rs index b0eed6e91..c6aa90c13 100644 --- a/rpc/tests/gaia_fixtures.rs +++ b/rpc/tests/gaia_fixtures.rs @@ -1,6 +1,9 @@ use std::{fs, path::PathBuf}; -use tendermint_rpc::{endpoint, event::Event, Request, Response}; +// TODO: generate fixtures and test with v0_37::dialect as well +use tendermint_rpc::dialect::v0_34::Event as RpcEvent; +use tendermint_rpc::{endpoint, event::DialectEvent, request::RequestMessage, Response}; + use walkdir::WalkDir; fn find_fixtures(in_out_folder_name: &str) -> Vec { @@ -51,11 +54,11 @@ fn incoming_fixtures() { assert!(r.is_ok(), "{r:?}"); }, "block_results_at_height_10" => { - let r = endpoint::block_results::Response::from_string(content); + let r = endpoint::block_results::DialectResponse::::from_string(content); assert!(r.is_ok(), "block_results_at_height_10: {r:?}"); }, "block_results_at_height_4555980" => { - let r = endpoint::block_results::Response::from_string(content); + let r = endpoint::block_results::DialectResponse::::from_string(content); assert!(r.is_ok(), "block_results_at_height_4555980: {r:?}"); }, "blockchain_from_1_to_10" => { @@ -87,7 +90,7 @@ fn incoming_fixtures() { }, _ => { if file_name.starts_with("subscribe_newblock_") { - let r = Event::from_string(content); + let r = DialectEvent::::from_string(content); assert!(r.is_ok(), "failed to parse event {file_name}: {r:?}"); } else { panic!("unhandled incoming fixture: {file_name}"); diff --git a/rpc/tests/kvstore_fixtures.rs b/rpc/tests/kvstore_fixtures.rs index 96d42e12b..76a31ea86 100644 --- a/rpc/tests/kvstore_fixtures.rs +++ b/rpc/tests/kvstore_fixtures.rs @@ -23,11 +23,19 @@ use walkdir::WalkDir; const CHAIN_ID: &str = "dockerchain"; -fn find_fixtures(in_out_folder_name: &str) -> Vec { +// Test modules in the kvstore_fixtures subdirectory +mod kvstore_fixtures { + use super::*; + mod v0_34; + mod v0_37; +} + +fn find_fixtures(ver_folder_name: &str, in_out_folder_name: &str) -> Vec { WalkDir::new( PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("tests") .join("kvstore_fixtures") + .join(ver_folder_name) .join(in_out_folder_name), ) .into_iter() @@ -40,1386 +48,3 @@ fn find_fixtures(in_out_folder_name: &str) -> Vec { .map(|e| e.into_path()) .collect::>() } - -#[test] -fn outgoing_fixtures() { - for json_file in find_fixtures("outgoing") { - let file_name = json_file - .file_name() - .unwrap() - .to_str() - .unwrap() - .strip_suffix(".json") - .unwrap(); - let content = fs::read_to_string(&json_file).unwrap(); - match file_name { - "abci_info" => assert!(serde_json::from_str::< - RequestWrapper, - >(&content) - .is_ok()), - "abci_query_with_existing_key" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert!(wrapped.params().path.is_none()); - assert_eq!(wrapped.params().data, hex::decode("747830").unwrap()); - assert!(wrapped.params().height.is_none()); - assert!(!wrapped.params().prove); - }, - "abci_query_with_non_existent_key" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert!(wrapped.params().path.is_none()); - assert_eq!( - wrapped.params().data, - hex::decode("6e6f6e5f6578697374656e745f6b6579").unwrap() - ); - assert!(wrapped.params().height.is_none()); - assert!(!wrapped.params().prove); - }, - "block_at_height_0" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().height.unwrap().value(), 0); - }, - "block_at_height_1" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().height.unwrap().value(), 1); - }, - "block_at_height_10" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().height.unwrap().value(), 10); - }, - "block_by_hash" => { - // First, get the hash at height 1. - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!( - wrapped.params().hash.unwrap().to_string(), - "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF" - ); - }, - "block_results_at_height_10" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!(wrapped.params().height.unwrap().value(), 10); - }, - "block_search" => { - let wrapped = - serde_json::from_str::>( - &content, - ) - .unwrap(); - assert_eq!(wrapped.params().query, "block.height > 1"); - assert_eq!(wrapped.params().page, 1); - assert_eq!(wrapped.params().per_page, 100); - assert_eq!(wrapped.params().order_by, Order::Ascending); - }, - "blockchain_from_1_to_10" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().min_height.value(), 1); - assert_eq!(wrapped.params().max_height.value(), 10); - }, - "broadcast_tx_async" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!( - wrapped.params().tx, - base64::decode("YXN5bmMta2V5PXZhbHVl").unwrap() - ); - }, - "broadcast_tx_commit" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!( - wrapped.params().tx, - base64::decode("Y29tbWl0LWtleT12YWx1ZQ==").unwrap() - ); - }, - "broadcast_tx_sync" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!( - wrapped.params().tx, - base64::decode("c3luYy1rZXk9dmFsdWU=").unwrap() - ); - }, - "commit_at_height_10" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().height.unwrap().value(), 10); - }, - "consensus_params" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - let height = wrapped.params().height.unwrap(); - assert_eq!(u64::from(height), 10u64); - }, - "consensus_state" => assert!(serde_json::from_str::< - RequestWrapper, - >(&content) - .is_ok()), - "genesis" => assert!(serde_json::from_str::< - RequestWrapper>, - >(&content) - .is_ok()), - "net_info" => assert!(serde_json::from_str::< - RequestWrapper, - >(&content) - .is_ok()), - "status" => assert!( - serde_json::from_str::>(&content).is_ok() - ), - "subscribe_malformed" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().query, "malformed query"); - }, - "subscribe_newblock" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().query, "tm.event = 'NewBlock'"); - }, - "subscribe_txs" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().query, "tm.event = 'Tx'"); - }, - "subscribe_txs_broadcast_tx_0" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!(wrapped.params().tx, base64::decode("dHgwPXZhbHVl").unwrap()); - }, - "subscribe_txs_broadcast_tx_1" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!(wrapped.params().tx, base64::decode("dHgxPXZhbHVl").unwrap()); - }, - "subscribe_txs_broadcast_tx_2" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!(wrapped.params().tx, base64::decode("dHgyPXZhbHVl").unwrap()); - }, - "subscribe_txs_broadcast_tx_3" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!(wrapped.params().tx, base64::decode("dHgzPXZhbHVl").unwrap()); - }, - "subscribe_txs_broadcast_tx_4" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!(wrapped.params().tx, base64::decode("dHg0PXZhbHVl").unwrap()); - }, - "subscribe_txs_broadcast_tx_5" => { - let wrapped = serde_json::from_str::< - RequestWrapper, - >(&content) - .unwrap(); - assert_eq!(wrapped.params().tx, base64::decode("dHg1PXZhbHVl").unwrap()); - }, - "tx" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!( - wrapped.params().hash, - Hash::from_bytes( - Algorithm::Sha256, - &[ - 214, 63, 156, 35, 121, 30, 97, 4, 16, 181, 118, 216, 194, 123, 181, - 174, 172, 147, 204, 26, 88, 82, 36, 40, 167, 179, 42, 18, 118, 8, 88, - 96 - ] - ) - .unwrap() - ); - assert!(!wrapped.params().prove); - }, - "tx_search_no_prove" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().query, "tx.height > 1"); - assert!(!wrapped.params().prove); - assert_eq!(wrapped.params().page, 1); - assert_eq!(wrapped.params().per_page, 10); - assert_eq!(wrapped.params().order_by, Order::Ascending); - }, - "tx_search_with_prove" => { - let wrapped = - serde_json::from_str::>(&content) - .unwrap(); - assert_eq!(wrapped.params().query, "tx.height > 1"); - assert!(wrapped.params().prove); - assert_eq!(wrapped.params().page, 1); - assert_eq!(wrapped.params().per_page, 10); - assert_eq!(wrapped.params().order_by, Order::Ascending); - }, - _ => { - panic!("cannot parse file name: {file_name}"); - }, - } - } -} - -#[test] -fn incoming_fixtures() { - let empty_merkle_root_hash = Some( - tendermint::Hash::from_hex_upper( - tendermint::hash::Algorithm::Sha256, - "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", - ) - .unwrap(), - ); - let informal_epoch = - tendermint::Time::parse_from_rfc3339("2020-01-01T00:00:00.000000000Z").unwrap(); - - for json_file in find_fixtures("incoming") { - let file_name = json_file - .file_name() - .unwrap() - .to_str() - .unwrap() - .strip_suffix(".json") - .unwrap(); - let content = fs::read_to_string(&json_file).unwrap(); - match file_name { - "abci_info" => { - let result = endpoint::abci_info::Response::from_string(content).unwrap(); - assert_eq!(result.response.app_version, 1); - assert_eq!(result.response.data, "{\"size\":0}"); - assert_eq!( - result.response.last_block_app_hash.as_bytes(), - b"AAAAAAAAAAA=" - ); - assert_eq!(result.response.version, "0.17.0"); - }, - "abci_query_with_existing_key" => { - let result = endpoint::abci_query::Response::from_string(content).unwrap(); - assert_eq!(result.response.code.value(), 0); - assert!(result.response.codespace.is_empty()); - assert_eq!(result.response.index, 0); - assert!(result.response.info.is_empty()); - assert_eq!(result.response.key, base64::decode("dHgw").unwrap()); - assert_eq!(result.response.log, "exists"); - assert!(result.response.proof.is_none()); - assert_eq!(result.response.value, base64::decode("dmFsdWU=").unwrap()); - }, - "abci_query_with_non_existent_key" => { - let result = endpoint::abci_query::Response::from_string(content).unwrap(); - assert_eq!(result.response.code.value(), 0); - assert!(result.response.codespace.is_empty()); - assert_eq!(result.response.index, 0); - assert!(result.response.info.is_empty()); - assert_eq!( - result.response.key, - base64::decode("bm9uX2V4aXN0ZW50X2tleQ==").unwrap() - ); - assert_eq!(result.response.log, "does not exist"); - assert!(result.response.proof.is_none()); - assert!(result.response.value.is_empty()); - }, - "block_at_height_0" => { - let res = endpoint::block::Response::from_string(&content); - - match res { - Err(Error(ErrorDetail::Response(e), _)) => { - let response = e.source; - assert_eq!(response.code(), Code::InternalError); - assert_eq!(response.message(), "Internal error"); - assert_eq!( - response.data(), - Some("height must be greater than 0, but got 0") - ); - }, - _ => panic!("expected Response error"), - } - }, - "block_at_height_1" => { - let result = endpoint::block::Response::from_string(content).unwrap(); - assert!(result.block.data.get(0).is_none()); - assert!(result.block.evidence.iter().next().is_none()); - assert!(result.block.header.app_hash.as_bytes().is_empty()); - assert_eq!(result.block.header.chain_id.as_str(), CHAIN_ID); - assert!(!result.block.header.consensus_hash.is_empty()); - assert_eq!(result.block.header.data_hash, empty_merkle_root_hash); - assert_eq!(result.block.header.evidence_hash, empty_merkle_root_hash); - assert_eq!(result.block.header.height.value(), 1); - assert!(result.block.header.last_block_id.is_none()); - assert_eq!(result.block.header.last_commit_hash, empty_merkle_root_hash); - assert_eq!( - result.block.header.last_results_hash, - empty_merkle_root_hash - ); - assert!(!result.block.header.next_validators_hash.is_empty()); - assert_ne!( - result.block.header.proposer_address.as_bytes(), - [0u8; tendermint::account::LENGTH] - ); - assert!( - result - .block - .header - .time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(!result.block.header.validators_hash.is_empty()); - assert_eq!( - result.block.header.version, - tendermint::block::header::Version { block: 11, app: 1 } - ); - assert!(result.block.last_commit.is_none()); - assert!(!result.block_id.hash.is_empty()); - assert!(!result.block_id.part_set_header.hash.is_empty()); - assert_eq!(result.block_id.part_set_header.total, 1); - }, - "block_at_height_10" => { - let result = endpoint::block::Response::from_string(content).unwrap(); - assert!(result.block.data.get(0).is_none()); - assert!(result.block.evidence.iter().next().is_none()); - assert_eq!(result.block.header.app_hash.as_bytes(), &[0u8; 8]); - assert_eq!(result.block.header.chain_id.as_str(), CHAIN_ID); - assert!(!result.block.header.consensus_hash.is_empty()); - assert_eq!(result.block.header.data_hash, empty_merkle_root_hash); - assert_eq!(result.block.header.evidence_hash, empty_merkle_root_hash); - assert_eq!(result.block.header.height.value(), 10); - assert!(result.block.header.last_block_id.is_some()); - assert!(result.block.header.last_commit_hash.is_some()); - assert!(result.block.header.last_results_hash.is_some()); - assert!(!result.block.header.next_validators_hash.is_empty()); - assert_ne!( - result.block.header.proposer_address.as_bytes(), - [0u8; tendermint::account::LENGTH] - ); - assert!( - result - .block - .header - .time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(!result.block.header.validators_hash.is_empty()); - assert_eq!( - result.block.header.version, - tendermint::block::header::Version { block: 11, app: 1 } - ); - let last_commit = result.block.last_commit.unwrap(); - assert!(!last_commit.block_id.hash.is_empty()); - assert!(!last_commit.block_id.part_set_header.hash.is_empty()); - assert_eq!(last_commit.block_id.part_set_header.total, 1); - assert_eq!(last_commit.height.value(), 9); - assert_eq!(last_commit.round.value(), 0); - assert_eq!(last_commit.signatures.len(), 1); - assert!(last_commit.signatures[0].is_commit()); - assert!(last_commit.signatures[0].validator_address().is_some()); - // It's weird but there is no implementation to get the signature out of CommitSig. - assert!(!result.block_id.hash.is_empty()); - assert!(!result.block_id.part_set_header.hash.is_empty()); - assert_eq!(result.block_id.part_set_header.total, 1); - }, - "block_results_at_height_10" => { - let result = endpoint::block_results::Response::from_string(content).unwrap(); - assert!(result.begin_block_events.is_none()); - assert!(result.consensus_param_updates.is_none()); - assert!(result.end_block_events.is_none()); - assert_eq!(result.height.value(), 10); - assert!(result.txs_results.is_none()); - assert!(result.validator_updates.is_empty()); - }, - "block_by_hash" => { - let result = endpoint::block::Response::from_string(content).unwrap(); - assert_eq!( - result.block_id.hash.to_string(), - "BCF3DB412E80A396D10BF5B5E6D3E63D3B06DEB25AA958BCB8CE18D023838042" - ); - }, - "block_search" => { - let result = endpoint::block_search::Response::from_string(content).unwrap(); - assert_eq!(result.total_count as usize, result.blocks.len()); - for response in result.blocks { - assert!(response.block.header.height.value() > 1); - } - }, - "block_search_evidence" => { - let result = endpoint::block_search::Response::from_string(content).unwrap(); - assert_eq!(result.total_count as usize, result.blocks.len()); - - // Test a few selected attributes of the results. - for block in result.blocks { - let evidence = block.block.evidence.iter().next().unwrap(); - - use tendermint::vote; - - fn check_vote(vote: &Vote) { - assert_eq!(vote.vote_type, vote::Type::Precommit); - assert_eq!(vote.height.value(), 8009); - assert_eq!(vote.round.value(), 0); - assert_eq!( - vote.validator_address, - "9319035301DA526CC78DCF174A47A74F81401291".parse().unwrap(), - ); - assert_eq!(vote.validator_index.value(), 8); - } - - if let Evidence::DuplicateVote(dup) = evidence { - assert_eq!(dup.total_voting_power.value(), 121); - assert_eq!(dup.validator_power.value(), 1); - assert_eq!( - dup.timestamp, - "2022-09-12T19:49:49.984608464Z".parse().unwrap() - ); - - check_vote(&dup.vote_a); - check_vote(&dup.vote_b); - } else { - panic!("not a duplicate vote: {evidence:?}"); - } - } - }, - "broadcast_tx_async" => { - let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, abci::Code::Ok); - assert!(result.data.is_empty()); - assert_ne!( - result.hash, - Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() - ); - assert!(result.log.is_empty()); - }, - "broadcast_tx_commit" => { - let result = - endpoint::broadcast::tx_commit::Response::from_string(content).unwrap(); - assert_eq!(result.check_tx.code, abci::Code::Ok); - assert!(result.check_tx.codespace.is_empty()); - assert!(result.check_tx.data.is_empty()); - assert!(result.check_tx.events.is_empty()); - assert_eq!(result.check_tx.gas_used, 0); - // Todo: https://github.com/informalsystems/tendermint-rs/issues/761 - // assert_eq!(result.check_tx.gas_wanted.value(), 1); - assert!(result.check_tx.info.to_string().is_empty()); - assert!(result.check_tx.log.is_empty()); - assert_eq!(result.deliver_tx.code, abci::Code::Ok); - assert!(result.deliver_tx.codespace.is_empty()); - assert!(result.deliver_tx.data.is_empty()); - assert_eq!(result.deliver_tx.events.len(), 1); - assert_eq!(result.deliver_tx.events[0].attributes.len(), 4); - assert_eq!(result.deliver_tx.events[0].attributes[0].key, "creator"); - assert_eq!( - result.deliver_tx.events[0].attributes[0].value, - "Cosmoshi Netowoko" - ); - assert_eq!(result.deliver_tx.events[0].attributes[1].key, "key"); - assert_eq!( - result.deliver_tx.events[0].attributes[1].value, - "commit-key" - ); - assert_eq!(result.deliver_tx.events[0].attributes[2].key, "index_key"); - assert_eq!( - result.deliver_tx.events[0].attributes[2].value, - "index is working" - ); - assert_eq!(result.deliver_tx.events[0].attributes[3].key, "noindex_key"); - assert_eq!( - result.deliver_tx.events[0].attributes[3].value, - "index is working" - ); - assert_eq!(result.deliver_tx.events[0].kind, "app"); - assert_eq!(result.deliver_tx.gas_used, 0); - assert_eq!(result.deliver_tx.gas_wanted, 0); - assert!(result.deliver_tx.info.to_string().is_empty()); - assert!(result.deliver_tx.log.is_empty()); - assert_ne!( - result.hash, - Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() - ); - }, - "broadcast_tx_sync" => { - let result = endpoint::broadcast::tx_sync::Response::from_string(content).unwrap(); - assert_eq!(result.code, abci::Code::Ok); - assert!(result.data.is_empty()); - assert_ne!( - result.hash, - Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() - ); - assert!(result.log.is_empty()); - }, - "commit_at_height_10" => { - let result = endpoint::commit::Response::from_string(content).unwrap(); - assert!(!result.signed_header.commit.block_id.hash.is_empty()); - assert_eq!(result.signed_header.commit.height.value(), 10); - assert_eq!(result.signed_header.commit.round.value(), 0); - assert_eq!(result.signed_header.commit.signatures.len(), 1); - assert!(result.signed_header.commit.signatures[0].is_commit()); - assert!(result.signed_header.commit.signatures[0] - .validator_address() - .is_some()); - assert_eq!(result.signed_header.header.app_hash.as_bytes(), [0u8; 8]); - assert_eq!(result.signed_header.header.chain_id.as_str(), CHAIN_ID); - assert!(!result.signed_header.header.consensus_hash.is_empty()); - assert_eq!( - result.signed_header.header.data_hash, - empty_merkle_root_hash - ); - assert_eq!( - result.signed_header.header.evidence_hash, - empty_merkle_root_hash - ); - assert_eq!(result.signed_header.header.height.value(), 10); - assert!(result.signed_header.header.last_block_id.is_some()); - assert!(result.signed_header.header.last_commit_hash.is_some()); - assert!(result.signed_header.header.last_results_hash.is_some()); - assert!(!result.signed_header.header.next_validators_hash.is_empty()); - assert_ne!( - result.signed_header.header.proposer_address.as_bytes(), - [0u8; tendermint::account::LENGTH] - ); - assert!( - result - .signed_header - .header - .time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(!result.signed_header.header.validators_hash.is_empty()); - assert_eq!( - result.signed_header.header.version, - tendermint::block::header::Version { block: 11, app: 1 } - ); - }, - "consensus_params" => { - let result = endpoint::consensus_params::Response::from_string(content).unwrap(); - assert_eq!(u64::from(result.block_height), 10_u64); - assert_eq!(result.consensus_params.block.max_bytes, 22020096_u64); - assert_eq!(result.consensus_params.block.max_gas, -1_i64); - assert_eq!(result.consensus_params.block.time_iota_ms, 500_i64); - assert_eq!( - result.consensus_params.evidence.max_age_duration, - Duration(core::time::Duration::from_nanos(172800000000000_u64)) - ); - assert_eq!( - result.consensus_params.evidence.max_age_num_blocks, - 100000_u64 - ); - assert_eq!(result.consensus_params.evidence.max_bytes, 1048576_i64); - assert_eq!( - result.consensus_params.validator.pub_key_types, - vec![public_key::Algorithm::Ed25519] - ); - }, - "consensus_state" => { - assert!(endpoint::consensus_state::Response::from_string(content).is_ok()); - }, - "genesis" => { - let result = - endpoint::genesis::Response::>::from_string(content) - .unwrap(); - assert!(result.genesis.app_hash.as_bytes().is_empty()); - assert_eq!(result.genesis.chain_id.as_str(), CHAIN_ID); - assert_eq!(result.genesis.consensus_params.block.max_bytes, 22020096); - assert_eq!(result.genesis.consensus_params.block.max_gas, -1); - assert_eq!( - result - .genesis - .consensus_params - .evidence - .max_age_duration - .0 - .as_nanos(), - 172800000000000 - ); - assert_eq!( - result.genesis.consensus_params.evidence.max_age_num_blocks, - 100000 - ); - assert_eq!(result.genesis.consensus_params.evidence.max_bytes, 1048576); - assert_eq!( - result - .genesis - .consensus_params - .validator - .pub_key_types - .len(), - 1 - ); - assert_eq!( - result.genesis.consensus_params.validator.pub_key_types[0], - tendermint::public_key::Algorithm::Ed25519 - ); - assert!(result.genesis.consensus_params.version.is_none()); - assert!( - result - .genesis - .genesis_time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert_eq!(result.genesis.validators.len(), 1); - assert_ne!( - result.genesis.validators[0].address.as_bytes(), - [0; tendermint::account::LENGTH] - ); - assert_eq!(result.genesis.validators[0].power(), 10); - assert!(result.genesis.validators[0].pub_key.ed25519().is_some()); - assert_eq!(result.genesis.validators[0].proposer_priority.value(), 0); - assert_eq!(result.genesis.consensus_params.block.time_iota_ms, 500); - }, - "net_info" => { - let result = endpoint::net_info::Response::from_string(content).unwrap(); - assert_eq!(result.listeners.len(), 1); - assert_eq!(result.listeners[0].to_string(), "Listener(@)"); - assert!(result.listening); - assert_eq!(result.n_peers, 0); - assert!(result.peers.is_empty()); - }, - "status" => { - let result = endpoint::status::Response::from_string(content).unwrap(); - assert_eq!( - Address::from_listen_address(&result.node_info.listen_addr).unwrap(), - Address::from_str("tcp://0.0.0.0:26656").unwrap() - ); - assert_eq!(result.node_info.moniker.to_string(), "dockernode"); - assert_eq!(result.node_info.network.to_string(), CHAIN_ID); - assert_eq!( - result.node_info.other.rpc_address, - format!("{}", Address::from_str("tcp://0.0.0.0:26657").unwrap()) - ); - assert_eq!( - result.node_info.other.tx_index, - tendermint::node::info::TxIndexStatus::On - ); - assert_eq!( - result.node_info.protocol_version, - tendermint::node::info::ProtocolVersionInfo { - p2p: 8, - block: 11, - app: 1 - } - ); - assert_eq!(result.node_info.version.to_string(), "0.34.21"); - assert!(!result.sync_info.catching_up); - assert_eq!( - result.sync_info.latest_app_hash.as_bytes(), - [6, 0, 0, 0, 0, 0, 0, 0] - ); - assert!(!result.sync_info.latest_block_hash.is_empty()); - assert!( - result - .sync_info - .latest_block_time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(result.validator_info.pub_key.ed25519().is_some()); - assert_eq!(result.validator_info.power.value(), 10); - }, - "blockchain_from_1_to_10" => { - let result = endpoint::blockchain::Response::from_string(content).unwrap(); - assert_eq!(result.block_metas.len(), 10); - for block_meta in result.block_metas { - assert!(!block_meta.block_id.hash.is_empty()); - assert!(!block_meta.block_id.part_set_header.hash.is_empty()); - assert_eq!(block_meta.block_id.part_set_header.total, 1); - assert!(block_meta.block_size > 0); - if block_meta.header.height.value() == 1 { - assert!(block_meta.header.app_hash.as_bytes().is_empty()); - assert_eq!(block_meta.header.data_hash, empty_merkle_root_hash); - assert_eq!(block_meta.header.evidence_hash, empty_merkle_root_hash); - assert!(block_meta.header.last_block_id.is_none()); - assert_eq!(block_meta.header.last_commit_hash, empty_merkle_root_hash); - assert_eq!(block_meta.header.last_results_hash, empty_merkle_root_hash); - } else { - assert!(!block_meta.header.app_hash.as_bytes().is_empty()); - assert!(block_meta.header.data_hash.is_some()); - assert!(block_meta.header.evidence_hash.is_some()); - assert!(block_meta.header.last_block_id.is_some()); - assert!(block_meta.header.last_commit_hash.is_some()); - assert!(block_meta.header.last_results_hash.is_some()); - } - assert_eq!(block_meta.header.chain_id.as_str(), CHAIN_ID); - assert!(!block_meta.header.consensus_hash.is_empty()); - assert!(!block_meta.header.next_validators_hash.is_empty()); - assert_ne!( - block_meta.header.proposer_address.as_bytes(), - [0u8; tendermint::account::LENGTH] - ); - assert!( - block_meta - .header - .time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(!block_meta.header.validators_hash.is_empty()); - assert_eq!( - block_meta.header.version, - tendermint::block::header::Version { block: 11, app: 1 } - ); - assert_eq!(block_meta.num_txs, 0); - } - }, - "subscribe_malformed" => { - let result = endpoint::subscribe::Response::from_string(content); - - match result { - Err(Error(ErrorDetail::Response(e), _)) => { - let response = e.source; - - assert_eq!(response.code(), Code::InternalError); - assert_eq!(response.message(), "Internal error"); - assert_eq!(response.data().unwrap(),"failed to parse query: \nparse error near PegText (line 1 symbol 2 - line 1 symbol 11):\n\"malformed\"\n"); - }, - _ => panic!("expected Response error"), - } - }, - "subscribe_newblock" => { - let result = endpoint::subscribe::Response::from_string(content); - - match result { - Err(Error(ErrorDetail::Serde(_), _)) => {}, - _ => panic!("expected Serde parse error, instead got {result:?}"), - } - }, - "subscribe_newblock_0" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - if let tendermint_rpc::event::EventData::NewBlock { - block, - result_begin_block, - result_end_block, - } = result.data - { - let b = block.unwrap(); - assert!(b.data.get(0).is_none()); - assert!(b.evidence.iter().next().is_none()); - assert!(!b.header.app_hash.as_bytes().is_empty()); - assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); - assert!(!b.header.consensus_hash.is_empty()); - assert_eq!(b.header.data_hash, empty_merkle_root_hash); - assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); - assert!(b.header.last_block_id.is_some()); - assert!(b.header.last_commit_hash.is_some()); - assert!(b.header.last_results_hash.is_some()); - assert!(!b.header.next_validators_hash.is_empty()); - assert_ne!( - b.header.proposer_address.as_bytes(), - [0u8; tendermint::account::LENGTH] - ); - assert!( - b.header - .time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(!b.header.validators_hash.is_empty()); - assert_eq!( - b.header.version, - tendermint::block::header::Version { block: 11, app: 1 } - ); - let last_commit = b.last_commit.unwrap(); - assert!(!last_commit.block_id.hash.is_empty()); - assert!(!last_commit.block_id.part_set_header.hash.is_empty()); - assert_eq!(last_commit.block_id.part_set_header.total, 1); - assert_eq!(last_commit.round.value(), 0); - assert_eq!(last_commit.signatures.len(), 1); - assert!(last_commit.signatures[0].is_commit()); - assert!(last_commit.signatures[0].validator_address().is_some()); - assert!(result_begin_block.unwrap().events.is_empty()); - let reb = result_end_block.unwrap(); - assert!(reb.validator_updates.is_empty()); - assert!(reb.consensus_param_updates.is_none()); - assert!(reb.events.is_empty()); - } else { - panic!("not a newblock"); - } - assert_eq!(result.query, "tm.event = 'NewBlock'"); - }, - "subscribe_newblock_1" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - if let tendermint_rpc::event::EventData::NewBlock { - block, - result_begin_block, - result_end_block, - } = result.data - { - let b = block.unwrap(); - assert!(b.data.get(0).is_none()); - assert!(b.evidence.iter().next().is_none()); - assert!(!b.header.app_hash.as_bytes().is_empty()); - assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); - assert!(!b.header.consensus_hash.is_empty()); - assert_eq!(b.header.data_hash, empty_merkle_root_hash); - assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); - assert!(b.header.last_block_id.is_some()); - assert!(b.header.last_commit_hash.is_some()); - assert!(b.header.last_results_hash.is_some()); - assert!(!b.header.next_validators_hash.is_empty()); - assert_ne!( - b.header.proposer_address.as_bytes(), - [0u8; tendermint::account::LENGTH] - ); - assert!( - b.header - .time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(!b.header.validators_hash.is_empty()); - assert_eq!( - b.header.version, - tendermint::block::header::Version { block: 11, app: 1 } - ); - let last_commit = b.last_commit.unwrap(); - assert!(!last_commit.block_id.hash.is_empty()); - assert!(!last_commit.block_id.part_set_header.hash.is_empty()); - assert_eq!(last_commit.block_id.part_set_header.total, 1); - assert_eq!(last_commit.round.value(), 0); - assert_eq!(last_commit.signatures.len(), 1); - assert!(last_commit.signatures[0].is_commit()); - assert!(last_commit.signatures[0].validator_address().is_some()); - let rbb = result_begin_block.unwrap(); - assert_eq!(rbb.events.len(), 2); - assert_eq!(rbb.events[0].kind, "transfer"); - assert_eq!(rbb.events[0].attributes.len(), 2); - assert_eq!(rbb.events[0].attributes[0].key, "recipient"); - assert_eq!( - rbb.events[0].attributes[0].value, - "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta" - ); - assert!(rbb.events[0].attributes[0].index); - assert_eq!(rbb.events[0].attributes[1].key, "sender"); - assert_eq!( - rbb.events[0].attributes[1].value, - "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q" - ); - assert!(!rbb.events[0].attributes[1].index); - assert_eq!(rbb.events[1].kind, "message"); - assert_eq!(rbb.events[1].attributes.len(), 1); - assert_eq!(rbb.events[1].attributes[0].key, "sender"); - assert_eq!( - rbb.events[1].attributes[0].value, - "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q" - ); - let reb = result_end_block.unwrap(); - assert!(reb.validator_updates.is_empty()); - assert!(reb.consensus_param_updates.is_none()); - assert!(reb.events.is_empty()); - } else { - panic!("not a newblock"); - } - assert_eq!(result.query, "tm.event = 'NewBlock'"); - }, - "subscribe_newblock_2" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - if let tendermint_rpc::event::EventData::NewBlock { - block, - result_begin_block, - result_end_block, - } = result.data - { - let b = block.unwrap(); - assert!(b.data.get(0).is_none()); - assert!(b.evidence.iter().next().is_none()); - assert!(!b.header.app_hash.as_bytes().is_empty()); - assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); - assert!(!b.header.consensus_hash.is_empty()); - assert_eq!(b.header.data_hash, empty_merkle_root_hash); - assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); - assert!(b.header.last_block_id.is_some()); - assert!(b.header.last_commit_hash.is_some()); - assert!(b.header.last_results_hash.is_some()); - assert!(!b.header.next_validators_hash.is_empty()); - assert_ne!( - b.header.proposer_address.as_bytes(), - [0u8; tendermint::account::LENGTH] - ); - assert!( - b.header - .time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(!b.header.validators_hash.is_empty()); - assert_eq!( - b.header.version, - tendermint::block::header::Version { block: 11, app: 1 } - ); - let last_commit = b.last_commit.unwrap(); - assert!(!last_commit.block_id.hash.is_empty()); - assert!(!last_commit.block_id.part_set_header.hash.is_empty()); - assert_eq!(last_commit.block_id.part_set_header.total, 1); - assert_eq!(last_commit.round.value(), 0); - assert_eq!(last_commit.signatures.len(), 1); - assert!(last_commit.signatures[0].is_commit()); - assert!(last_commit.signatures[0].validator_address().is_some()); - assert!(result_begin_block.unwrap().events.is_empty()); - let reb = result_end_block.unwrap(); - assert!(reb.validator_updates.is_empty()); - assert!(reb.consensus_param_updates.is_none()); - assert!(reb.events.is_empty()); - } else { - panic!("not a newblock"); - } - assert_eq!(result.query, "tm.event = 'NewBlock'"); - }, - "subscribe_newblock_3" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - if let tendermint_rpc::event::EventData::NewBlock { - block, - result_begin_block, - result_end_block, - } = result.data - { - let b = block.unwrap(); - assert!(b.data.get(0).is_none()); - assert!(b.evidence.iter().next().is_none()); - assert!(!b.header.app_hash.as_bytes().is_empty()); - assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); - assert!(!b.header.consensus_hash.is_empty()); - assert_eq!(b.header.data_hash, empty_merkle_root_hash); - assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); - assert!(b.header.last_block_id.is_some()); - assert!(b.header.last_commit_hash.is_some()); - assert!(b.header.last_results_hash.is_some()); - assert!(!b.header.next_validators_hash.is_empty()); - assert_ne!( - b.header.proposer_address.as_bytes(), - [0u8; tendermint::account::LENGTH] - ); - assert!( - b.header - .time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(!b.header.validators_hash.is_empty()); - assert_eq!( - b.header.version, - tendermint::block::header::Version { block: 11, app: 1 } - ); - let last_commit = b.last_commit.unwrap(); - assert!(!last_commit.block_id.hash.is_empty()); - assert!(!last_commit.block_id.part_set_header.hash.is_empty()); - assert_eq!(last_commit.block_id.part_set_header.total, 1); - assert_eq!(last_commit.round.value(), 0); - assert_eq!(last_commit.signatures.len(), 1); - assert!(last_commit.signatures[0].is_commit()); - assert!(last_commit.signatures[0].validator_address().is_some()); - assert!(result_begin_block.unwrap().events.is_empty()); - let reb = result_end_block.unwrap(); - assert!(reb.validator_updates.is_empty()); - assert!(reb.consensus_param_updates.is_none()); - assert!(reb.events.is_empty()); - } else { - panic!("not a newblock"); - } - assert_eq!(result.query, "tm.event = 'NewBlock'"); - }, - "subscribe_newblock_4" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - if let tendermint_rpc::event::EventData::NewBlock { - block, - result_begin_block, - result_end_block, - } = result.data - { - let b = block.unwrap(); - assert!(b.data.get(0).is_none()); - assert!(b.evidence.iter().next().is_none()); - assert!(!b.header.app_hash.as_bytes().is_empty()); - assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); - assert!(!b.header.consensus_hash.is_empty()); - assert_eq!(b.header.data_hash, empty_merkle_root_hash); - assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); - assert!(b.header.last_block_id.is_some()); - assert!(b.header.last_commit_hash.is_some()); - assert!(b.header.last_results_hash.is_some()); - assert!(!b.header.next_validators_hash.is_empty()); - assert_ne!( - b.header.proposer_address.as_bytes(), - [0u8; tendermint::account::LENGTH] - ); - assert!( - b.header - .time - .duration_since(informal_epoch) - .unwrap() - .as_secs() - > 0 - ); - assert!(!b.header.validators_hash.is_empty()); - assert_eq!( - b.header.version, - tendermint::block::header::Version { block: 11, app: 1 } - ); - let last_commit = b.last_commit.unwrap(); - assert!(!last_commit.block_id.hash.is_empty()); - assert!(!last_commit.block_id.part_set_header.hash.is_empty()); - assert_eq!(last_commit.block_id.part_set_header.total, 1); - assert_eq!(last_commit.round.value(), 0); - assert_eq!(last_commit.signatures.len(), 1); - assert!(last_commit.signatures[0].is_commit()); - assert!(last_commit.signatures[0].validator_address().is_some()); - assert!(result_begin_block.unwrap().events.is_empty()); - let reb = result_end_block.unwrap(); - assert!(reb.validator_updates.is_empty()); - assert!(reb.consensus_param_updates.is_none()); - assert!(reb.events.is_empty()); - } else { - panic!("not a newblock"); - } - assert_eq!(result.query, "tm.event = 'NewBlock'"); - }, - "subscribe_txs" => { - assert!(endpoint::subscribe::Response::from_string(content).is_ok()); - }, - "subscribe_txs_0" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - let height; - if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data { - height = tx_result.height; - assert!(tx_result.result.log.is_none()); - assert!(tx_result.result.gas_wanted.is_none()); - assert!(tx_result.result.gas_used.is_none()); - assert_eq!(tx_result.result.events.len(), 1); - assert_eq!(tx_result.result.events[0].kind, "app"); - for attr in &tx_result.result.events[0].attributes { - match attr.key.as_str() { - "creator" => { - assert_eq!(attr.value, "Cosmoshi Netowoko") - }, - "key" => assert_eq!(attr.value, "tx0"), - "index_key" => { - assert_eq!(attr.value, "index is working") - }, - "noindex_key" => { - assert_eq!(attr.value, "index is working") - }, - _ => panic!("unknown attribute found {}", attr.key), - } - } - assert_eq!(tx_result.tx, base64::decode("dHgwPXZhbHVl").unwrap()); - } else { - panic!("not a tx"); - } - check_event_attrs(&result.events.unwrap(), "tx0", height); - assert_eq!(result.query, "tm.event = 'Tx'"); - }, - "subscribe_txs_1" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - let height; - if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data { - height = tx_result.height; - assert!(tx_result.result.log.is_none()); - assert!(tx_result.result.gas_wanted.is_none()); - assert!(tx_result.result.gas_used.is_none()); - assert_eq!(tx_result.result.events.len(), 1); - assert_eq!(tx_result.result.events[0].kind, "app"); - for attr in &tx_result.result.events[0].attributes { - match attr.key.as_str() { - "creator" => { - assert_eq!(attr.value, "Cosmoshi Netowoko") - }, - "key" => assert_eq!(attr.value, "tx1"), - "index_key" => { - assert_eq!(attr.value, "index is working") - }, - "noindex_key" => { - assert_eq!(attr.value, "index is working") - }, - _ => panic!("unknown attribute found {}", attr.key), - } - } - assert_eq!(tx_result.tx, base64::decode("dHgxPXZhbHVl").unwrap()); - } else { - panic!("not a tx"); - } - - check_event_attrs(&result.events.unwrap(), "tx1", height); - assert_eq!(result.query, "tm.event = 'Tx'"); - }, - "subscribe_txs_2" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - let height; - if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data { - height = tx_result.height; - assert!(tx_result.result.log.is_none()); - assert!(tx_result.result.gas_wanted.is_none()); - assert!(tx_result.result.gas_used.is_none()); - assert_eq!(tx_result.result.events.len(), 1); - assert_eq!(tx_result.result.events[0].kind, "app"); - for attr in &tx_result.result.events[0].attributes { - match attr.key.as_str() { - "creator" => { - assert_eq!(attr.value, "Cosmoshi Netowoko") - }, - "key" => assert_eq!(attr.value, "tx2"), - "index_key" => { - assert_eq!(attr.value, "index is working") - }, - "noindex_key" => { - assert_eq!(attr.value, "index is working") - }, - _ => panic!("unknown attribute found {}", attr.key), - } - } - assert_eq!(tx_result.tx, base64::decode("dHgyPXZhbHVl").unwrap()); - } else { - panic!("not a tx"); - } - check_event_attrs(&result.events.unwrap(), "tx2", height); - assert_eq!(result.query, "tm.event = 'Tx'"); - }, - "subscribe_txs_3" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - let height; - if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data { - height = tx_result.height; - assert!(tx_result.result.log.is_none()); - assert!(tx_result.result.gas_wanted.is_none()); - assert!(tx_result.result.gas_used.is_none()); - assert_eq!(tx_result.result.events.len(), 1); - assert_eq!(tx_result.result.events[0].kind, "app"); - for attr in &tx_result.result.events[0].attributes { - match attr.key.as_str() { - "creator" => { - assert_eq!(attr.value, "Cosmoshi Netowoko") - }, - "key" => assert_eq!(attr.value, "tx3"), - "index_key" => { - assert_eq!(attr.value, "index is working") - }, - "noindex_key" => { - assert_eq!(attr.value, "index is working") - }, - _ => panic!("unknown attribute found {}", attr.key), - } - } - assert_eq!(tx_result.tx, base64::decode("dHgzPXZhbHVl").unwrap()); - } else { - panic!("not a tx"); - } - check_event_attrs(&result.events.unwrap(), "tx3", height); - assert_eq!(result.query, "tm.event = 'Tx'"); - }, - "subscribe_txs_4" => { - let result = tendermint_rpc::event::Event::from_string(content).unwrap(); - let height; - if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data { - height = tx_result.height; - assert!(tx_result.result.log.is_none()); - assert!(tx_result.result.gas_wanted.is_none()); - assert!(tx_result.result.gas_used.is_none()); - assert_eq!(tx_result.result.events.len(), 1); - assert_eq!(tx_result.result.events[0].kind, "app"); - for attr in &tx_result.result.events[0].attributes { - match attr.key.as_str() { - "creator" => { - assert_eq!(attr.value, "Cosmoshi Netowoko") - }, - "key" => assert_eq!(attr.value, "tx4"), - "index_key" => { - assert_eq!(attr.value, "index is working") - }, - "noindex_key" => { - assert_eq!(attr.value, "index is working") - }, - _ => panic!("unknown attribute found {}", attr.key), - } - } - assert_eq!(tx_result.tx, base64::decode("dHg0PXZhbHVl").unwrap()); - } else { - panic!("not a tx"); - } - check_event_attrs(&result.events.unwrap(), "tx4", height); - assert_eq!(result.query, "tm.event = 'Tx'"); - }, - "subscribe_txs_broadcast_tx_0" => { - let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, abci::Code::Ok); - assert!(result.data.is_empty()); - assert_ne!( - result.hash, - Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() - ); - assert!(result.log.is_empty()); - }, - "subscribe_txs_broadcast_tx_1" => { - let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, abci::Code::Ok); - assert!(result.data.is_empty()); - assert_ne!( - result.hash, - Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() - ); - assert!(result.log.is_empty()); - }, - "subscribe_txs_broadcast_tx_2" => { - let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, abci::Code::Ok); - assert!(result.data.is_empty()); - assert_ne!( - result.hash, - Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() - ); - assert!(result.log.is_empty()); - }, - "subscribe_txs_broadcast_tx_3" => { - let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, abci::Code::Ok); - assert!(result.data.is_empty()); - assert_ne!( - result.hash, - Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() - ); - assert!(result.log.is_empty()); - }, - "subscribe_txs_broadcast_tx_4" => { - let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, abci::Code::Ok); - assert!(result.data.is_empty()); - assert_ne!( - result.hash, - Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() - ); - assert!(result.log.is_empty()); - }, - "subscribe_txs_broadcast_tx_5" => { - let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, abci::Code::Ok); - assert!(result.data.is_empty()); - assert_ne!( - result.hash, - Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() - ); - assert!(result.log.is_empty()); - }, - "tx" => { - let result = endpoint::tx::Response::from_string(content).unwrap(); - assert_eq!( - result.hash, - Hash::from_bytes( - Algorithm::Sha256, - &[ - 214, 63, 156, 35, 121, 30, 97, 4, 16, 181, 118, 216, 194, 123, 181, - 174, 172, 147, 204, 26, 88, 82, 36, 40, 167, 179, 42, 18, 118, 8, 88, - 96 - ] - ) - .unwrap() - ); - assert_eq!(u64::from(result.height), 12u64); - }, - "tx_search_no_prove" => { - let result = endpoint::tx_search::Response::from_string(content).unwrap(); - assert_eq!(result.total_count as usize, result.txs.len()); - // Test a few selected attributes of the results. - for tx in result.txs { - assert_ne!(tx.hash.as_bytes(), [0; 32]); - assert_eq!(tx.tx_result.code, abci::Code::Ok); - assert_eq!(tx.tx_result.events.len(), 1); - assert_eq!(tx.tx_result.events[0].kind, "app"); - assert_eq!(tx.tx_result.gas_used, 0); - assert_eq!(tx.tx_result.gas_wanted, 0); - assert!(tx.tx_result.info.to_string().is_empty()); - assert!(tx.tx_result.log.is_empty()); - assert!(tx.proof.is_none()); - } - }, - "tx_search_with_prove" => { - let result = endpoint::tx_search::Response::from_string(content).unwrap(); - assert_eq!(result.total_count as usize, result.txs.len()); - // Test a few selected attributes of the results. - for tx in result.txs { - assert_ne!(tx.hash.as_bytes(), [0; 32]); - assert_eq!(tx.tx_result.code, abci::Code::Ok); - assert_eq!(tx.tx_result.events.len(), 1); - assert_eq!(tx.tx_result.events[0].kind, "app"); - assert_eq!(tx.tx_result.gas_used, 0); - assert_eq!(tx.tx_result.gas_wanted, 0); - assert!(tx.tx_result.info.to_string().is_empty()); - assert!(tx.tx_result.log.is_empty()); - let proof = tx.proof.unwrap(); - assert_eq!(proof.data, tx.tx); - assert_eq!(proof.proof.total, 1); - assert_eq!(proof.proof.index, 0); - assert_ne!(proof.root_hash.as_bytes(), [0; 32]); - } - }, - _ => { - panic!("cannot parse file name: {file_name}"); - }, - } - } -} - -fn check_event_attrs(events: &HashMap>, app_key: &str, height: i64) { - for (k, v) in events { - assert_eq!(v.len(), 1); - match k.as_str() { - "app.creator" => assert_eq!(v[0], "Cosmoshi Netowoko"), - "app.index_key" => assert_eq!(v[0], "index is working"), - "app.key" => assert_eq!(v[0], app_key), - "app.noindex_key" => assert_eq!(v[0], "index is working"), - "tm.event" => assert_eq!(v[0], "Tx"), - "tx.hash" => assert_eq!(v[0].len(), 64), - "tx.height" => assert_eq!(v[0], height.to_string()), - _ => panic!("unknown event found {k}"), - } - } -} diff --git a/rpc/tests/kvstore_fixtures/v0_34.rs b/rpc/tests/kvstore_fixtures/v0_34.rs new file mode 100644 index 000000000..8b8d528ab --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_34.rs @@ -0,0 +1,1412 @@ +use super::*; + +#[test] +fn outgoing_fixtures() { + for json_file in find_fixtures("v0_34", "outgoing") { + let file_name = json_file + .file_name() + .unwrap() + .to_str() + .unwrap() + .strip_suffix(".json") + .unwrap(); + let content = fs::read_to_string(&json_file).unwrap(); + match file_name { + "abci_info" => assert!(serde_json::from_str::< + RequestWrapper, + >(&content) + .is_ok()), + "abci_query_with_existing_key" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert!(wrapped.params().path.is_none()); + assert_eq!(wrapped.params().data, hex::decode("747830").unwrap()); + assert!(wrapped.params().height.is_none()); + assert!(!wrapped.params().prove); + }, + "abci_query_with_non_existent_key" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert!(wrapped.params().path.is_none()); + assert_eq!( + wrapped.params().data, + hex::decode("6e6f6e5f6578697374656e745f6b6579").unwrap() + ); + assert!(wrapped.params().height.is_none()); + assert!(!wrapped.params().prove); + }, + "block_at_height_0" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 0); + }, + "block_at_height_1" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 1); + }, + "block_at_height_10" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 10); + }, + "block_by_hash" => { + // First, get the hash at height 1. + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!( + wrapped.params().hash.unwrap().to_string(), + "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF" + ); + }, + "block_results_at_height_10" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 10); + }, + "block_search" => { + let wrapped = + serde_json::from_str::>( + &content, + ) + .unwrap(); + assert_eq!(wrapped.params().query, "block.height > 1"); + assert_eq!(wrapped.params().page, 1); + assert_eq!(wrapped.params().per_page, 100); + assert_eq!(wrapped.params().order_by, Order::Ascending); + }, + "blockchain_from_1_to_10" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().min_height.value(), 1); + assert_eq!(wrapped.params().max_height.value(), 10); + }, + "broadcast_tx_async" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!( + wrapped.params().tx, + base64::decode("YXN5bmMta2V5PXZhbHVl").unwrap() + ); + }, + "broadcast_tx_commit" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!( + wrapped.params().tx, + base64::decode("Y29tbWl0LWtleT12YWx1ZQ==").unwrap() + ); + }, + "broadcast_tx_sync" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!( + wrapped.params().tx, + base64::decode("c3luYy1rZXk9dmFsdWU=").unwrap() + ); + }, + "commit_at_height_10" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 10); + }, + "consensus_params" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + let height = wrapped.params().height.unwrap(); + assert_eq!(u64::from(height), 10u64); + }, + "consensus_state" => assert!(serde_json::from_str::< + RequestWrapper, + >(&content) + .is_ok()), + "genesis" => assert!(serde_json::from_str::< + RequestWrapper>, + >(&content) + .is_ok()), + "net_info" => assert!(serde_json::from_str::< + RequestWrapper, + >(&content) + .is_ok()), + "status" => assert!( + serde_json::from_str::>(&content).is_ok() + ), + "subscribe_malformed" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "malformed query"); + }, + "subscribe_newblock" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "tm.event = 'NewBlock'"); + }, + "subscribe_txs" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "tm.event = 'Tx'"); + }, + "subscribe_txs_broadcast_tx_0" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHgwPXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_1" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHgxPXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_2" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHgyPXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_3" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHgzPXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_4" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHg0PXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_5" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHg1PXZhbHVl").unwrap()); + }, + "tx" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!( + wrapped.params().hash, + Hash::from_bytes( + Algorithm::Sha256, + &[ + 214, 63, 156, 35, 121, 30, 97, 4, 16, 181, 118, 216, 194, 123, 181, + 174, 172, 147, 204, 26, 88, 82, 36, 40, 167, 179, 42, 18, 118, 8, 88, + 96 + ] + ) + .unwrap() + ); + assert!(!wrapped.params().prove); + }, + "tx_search_no_prove" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "tx.height > 1"); + assert!(!wrapped.params().prove); + assert_eq!(wrapped.params().page, 1); + assert_eq!(wrapped.params().per_page, 10); + assert_eq!(wrapped.params().order_by, Order::Ascending); + }, + "tx_search_with_prove" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "tx.height > 1"); + assert!(wrapped.params().prove); + assert_eq!(wrapped.params().page, 1); + assert_eq!(wrapped.params().per_page, 10); + assert_eq!(wrapped.params().order_by, Order::Ascending); + }, + _ => { + panic!("cannot parse file name: {file_name}"); + }, + } + } +} + +#[test] +fn incoming_fixtures() { + use tendermint_rpc::dialect::v0_34::Event as RpcEvent; + + let empty_merkle_root_hash = Some( + tendermint::Hash::from_hex_upper( + tendermint::hash::Algorithm::Sha256, + "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + ) + .unwrap(), + ); + let informal_epoch = + tendermint::Time::parse_from_rfc3339("2020-01-01T00:00:00.000000000Z").unwrap(); + + for json_file in find_fixtures("v0_34", "incoming") { + let file_name = json_file + .file_name() + .unwrap() + .to_str() + .unwrap() + .strip_suffix(".json") + .unwrap(); + let content = fs::read_to_string(&json_file).unwrap(); + match file_name { + "abci_info" => { + let result = endpoint::abci_info::Response::from_string(content).unwrap(); + assert_eq!(result.response.app_version, 1); + assert_eq!(result.response.data, "{\"size\":0}"); + assert_eq!( + result.response.last_block_app_hash.as_bytes(), + b"AAAAAAAAAAA=" + ); + assert_eq!(result.response.version, "0.17.0"); + }, + "abci_query_with_existing_key" => { + let result = endpoint::abci_query::Response::from_string(content).unwrap(); + assert_eq!(result.response.code.value(), 0); + assert!(result.response.codespace.is_empty()); + assert_eq!(result.response.index, 0); + assert!(result.response.info.is_empty()); + assert_eq!(result.response.key, base64::decode("dHgw").unwrap()); + assert_eq!(result.response.log, "exists"); + assert!(result.response.proof.is_none()); + assert_eq!(result.response.value, base64::decode("dmFsdWU=").unwrap()); + }, + "abci_query_with_non_existent_key" => { + let result = endpoint::abci_query::Response::from_string(content).unwrap(); + assert_eq!(result.response.code.value(), 0); + assert!(result.response.codespace.is_empty()); + assert_eq!(result.response.index, 0); + assert!(result.response.info.is_empty()); + assert_eq!( + result.response.key, + base64::decode("bm9uX2V4aXN0ZW50X2tleQ==").unwrap() + ); + assert_eq!(result.response.log, "does not exist"); + assert!(result.response.proof.is_none()); + assert!(result.response.value.is_empty()); + }, + "block_at_height_0" => { + let res = endpoint::block::Response::from_string(&content); + + match res { + Err(Error(ErrorDetail::Response(e), _)) => { + let response = e.source; + assert_eq!(response.code(), Code::InternalError); + assert_eq!(response.message(), "Internal error"); + assert_eq!( + response.data(), + Some("height must be greater than 0, but got 0") + ); + }, + _ => panic!("expected Response error"), + } + }, + "block_at_height_1" => { + let result = endpoint::block::Response::from_string(content).unwrap(); + assert!(result.block.data.get(0).is_none()); + assert!(result.block.evidence.iter().next().is_none()); + assert!(result.block.header.app_hash.as_bytes().is_empty()); + assert_eq!(result.block.header.chain_id.as_str(), CHAIN_ID); + assert!(!result.block.header.consensus_hash.is_empty()); + assert_eq!(result.block.header.data_hash, empty_merkle_root_hash); + assert_eq!(result.block.header.evidence_hash, empty_merkle_root_hash); + assert_eq!(result.block.header.height.value(), 1); + assert!(result.block.header.last_block_id.is_none()); + assert_eq!(result.block.header.last_commit_hash, empty_merkle_root_hash); + assert_eq!( + result.block.header.last_results_hash, + empty_merkle_root_hash + ); + assert!(!result.block.header.next_validators_hash.is_empty()); + assert_ne!( + result.block.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + result + .block + .header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!result.block.header.validators_hash.is_empty()); + assert_eq!( + result.block.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + assert!(result.block.last_commit.is_none()); + assert!(!result.block_id.hash.is_empty()); + assert!(!result.block_id.part_set_header.hash.is_empty()); + assert_eq!(result.block_id.part_set_header.total, 1); + }, + "block_at_height_10" => { + let result = endpoint::block::Response::from_string(content).unwrap(); + assert!(result.block.data.get(0).is_none()); + assert!(result.block.evidence.iter().next().is_none()); + assert_eq!(result.block.header.app_hash.as_bytes(), &[0u8; 8]); + assert_eq!(result.block.header.chain_id.as_str(), CHAIN_ID); + assert!(!result.block.header.consensus_hash.is_empty()); + assert_eq!(result.block.header.data_hash, empty_merkle_root_hash); + assert_eq!(result.block.header.evidence_hash, empty_merkle_root_hash); + assert_eq!(result.block.header.height.value(), 10); + assert!(result.block.header.last_block_id.is_some()); + assert!(result.block.header.last_commit_hash.is_some()); + assert!(result.block.header.last_results_hash.is_some()); + assert!(!result.block.header.next_validators_hash.is_empty()); + assert_ne!( + result.block.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + result + .block + .header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!result.block.header.validators_hash.is_empty()); + assert_eq!( + result.block.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = result.block.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.height.value(), 9); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + // It's weird but there is no implementation to get the signature out of CommitSig. + assert!(!result.block_id.hash.is_empty()); + assert!(!result.block_id.part_set_header.hash.is_empty()); + assert_eq!(result.block_id.part_set_header.total, 1); + }, + "block_results_at_height_10" => { + let result: endpoint::block_results::Response = + endpoint::block_results::DialectResponse::::from_string(content) + .unwrap() + .into(); + assert!(result.begin_block_events.is_none()); + assert!(result.consensus_param_updates.is_none()); + assert!(result.end_block_events.is_none()); + assert_eq!(result.height.value(), 10); + assert!(result.txs_results.is_none()); + assert!(result.validator_updates.is_empty()); + }, + "block_by_hash" => { + let result = endpoint::block_by_hash::Response::from_string(content).unwrap(); + assert_eq!( + result.block_id.hash.to_string(), + "BCF3DB412E80A396D10BF5B5E6D3E63D3B06DEB25AA958BCB8CE18D023838042" + ); + }, + "block_search" => { + let result = endpoint::block_search::Response::from_string(content).unwrap(); + assert_eq!(result.total_count as usize, result.blocks.len()); + for response in result.blocks { + assert!(response.block.header.height.value() > 1); + } + }, + "block_search_evidence" => { + let result = endpoint::block_search::Response::from_string(content).unwrap(); + assert_eq!(result.total_count as usize, result.blocks.len()); + + // Test a few selected attributes of the results. + for block in result.blocks { + let evidence = block.block.evidence.iter().next().unwrap(); + + use tendermint::vote; + + fn check_vote(vote: &Vote) { + assert_eq!(vote.vote_type, vote::Type::Precommit); + assert_eq!(vote.height.value(), 8009); + assert_eq!(vote.round.value(), 0); + assert_eq!( + vote.validator_address, + "9319035301DA526CC78DCF174A47A74F81401291".parse().unwrap(), + ); + assert_eq!(vote.validator_index.value(), 8); + } + + if let Evidence::DuplicateVote(dup) = evidence { + assert_eq!(dup.total_voting_power.value(), 121); + assert_eq!(dup.validator_power.value(), 1); + assert_eq!( + dup.timestamp, + "2022-09-12T19:49:49.984608464Z".parse().unwrap() + ); + + check_vote(&dup.vote_a); + check_vote(&dup.vote_b); + } else { + panic!("not a duplicate vote: {evidence:?}"); + } + } + }, + "broadcast_tx_async" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "broadcast_tx_commit" => { + let result: endpoint::broadcast::tx_commit::Response = + endpoint::broadcast::tx_commit::DialectResponse::::from_string( + content, + ) + .unwrap() + .into(); + assert_eq!(result.check_tx.code, abci::Code::Ok); + assert!(result.check_tx.codespace.is_empty()); + assert!(result.check_tx.data.is_empty()); + assert!(result.check_tx.events.is_empty()); + assert_eq!(result.check_tx.gas_used, 0); + // Todo: https://github.com/informalsystems/tendermint-rs/issues/761 + // assert_eq!(result.check_tx.gas_wanted.value(), 1); + assert!(result.check_tx.info.to_string().is_empty()); + assert!(result.check_tx.log.is_empty()); + assert_eq!(result.deliver_tx.code, abci::Code::Ok); + assert!(result.deliver_tx.codespace.is_empty()); + assert!(result.deliver_tx.data.is_empty()); + assert_eq!(result.deliver_tx.events.len(), 1); + assert_eq!(result.deliver_tx.events[0].attributes.len(), 4); + assert_eq!(result.deliver_tx.events[0].attributes[0].key, "creator"); + assert_eq!( + result.deliver_tx.events[0].attributes[0].value, + "Cosmoshi Netowoko" + ); + assert_eq!(result.deliver_tx.events[0].attributes[1].key, "key"); + assert_eq!( + result.deliver_tx.events[0].attributes[1].value, + "commit-key" + ); + assert_eq!(result.deliver_tx.events[0].attributes[2].key, "index_key"); + assert_eq!( + result.deliver_tx.events[0].attributes[2].value, + "index is working" + ); + assert_eq!(result.deliver_tx.events[0].attributes[3].key, "noindex_key"); + assert_eq!( + result.deliver_tx.events[0].attributes[3].value, + "index is working" + ); + assert_eq!(result.deliver_tx.events[0].kind, "app"); + assert_eq!(result.deliver_tx.gas_used, 0); + assert_eq!(result.deliver_tx.gas_wanted, 0); + assert!(result.deliver_tx.info.to_string().is_empty()); + assert!(result.deliver_tx.log.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + }, + "broadcast_tx_sync" => { + let result = endpoint::broadcast::tx_sync::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "commit_at_height_10" => { + let result = endpoint::commit::Response::from_string(content).unwrap(); + assert!(!result.signed_header.commit.block_id.hash.is_empty()); + assert_eq!(result.signed_header.commit.height.value(), 10); + assert_eq!(result.signed_header.commit.round.value(), 0); + assert_eq!(result.signed_header.commit.signatures.len(), 1); + assert!(result.signed_header.commit.signatures[0].is_commit()); + assert!(result.signed_header.commit.signatures[0] + .validator_address() + .is_some()); + assert_eq!(result.signed_header.header.app_hash.as_bytes(), [0u8; 8]); + assert_eq!(result.signed_header.header.chain_id.as_str(), CHAIN_ID); + assert!(!result.signed_header.header.consensus_hash.is_empty()); + assert_eq!( + result.signed_header.header.data_hash, + empty_merkle_root_hash + ); + assert_eq!( + result.signed_header.header.evidence_hash, + empty_merkle_root_hash + ); + assert_eq!(result.signed_header.header.height.value(), 10); + assert!(result.signed_header.header.last_block_id.is_some()); + assert!(result.signed_header.header.last_commit_hash.is_some()); + assert!(result.signed_header.header.last_results_hash.is_some()); + assert!(!result.signed_header.header.next_validators_hash.is_empty()); + assert_ne!( + result.signed_header.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + result + .signed_header + .header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!result.signed_header.header.validators_hash.is_empty()); + assert_eq!( + result.signed_header.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + }, + "consensus_params" => { + let result = endpoint::consensus_params::Response::from_string(content).unwrap(); + assert_eq!(u64::from(result.block_height), 10_u64); + assert_eq!(result.consensus_params.block.max_bytes, 22020096_u64); + assert_eq!(result.consensus_params.block.max_gas, -1_i64); + assert_eq!(result.consensus_params.block.time_iota_ms, 500_i64); + assert_eq!( + result.consensus_params.evidence.max_age_duration, + Duration(core::time::Duration::from_nanos(172800000000000_u64)) + ); + assert_eq!( + result.consensus_params.evidence.max_age_num_blocks, + 100000_u64 + ); + assert_eq!(result.consensus_params.evidence.max_bytes, 1048576_i64); + assert_eq!( + result.consensus_params.validator.pub_key_types, + vec![public_key::Algorithm::Ed25519] + ); + }, + "consensus_state" => { + assert!(endpoint::consensus_state::Response::from_string(content).is_ok()); + }, + "genesis" => { + let result = + endpoint::genesis::Response::>::from_string(content) + .unwrap(); + assert!(result.genesis.app_hash.as_bytes().is_empty()); + assert_eq!(result.genesis.chain_id.as_str(), CHAIN_ID); + assert_eq!(result.genesis.consensus_params.block.max_bytes, 22020096); + assert_eq!(result.genesis.consensus_params.block.max_gas, -1); + assert_eq!( + result + .genesis + .consensus_params + .evidence + .max_age_duration + .0 + .as_nanos(), + 172800000000000 + ); + assert_eq!( + result.genesis.consensus_params.evidence.max_age_num_blocks, + 100000 + ); + assert_eq!(result.genesis.consensus_params.evidence.max_bytes, 1048576); + assert_eq!( + result + .genesis + .consensus_params + .validator + .pub_key_types + .len(), + 1 + ); + assert_eq!( + result.genesis.consensus_params.validator.pub_key_types[0], + tendermint::public_key::Algorithm::Ed25519 + ); + assert!(result.genesis.consensus_params.version.is_none()); + assert!( + result + .genesis + .genesis_time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert_eq!(result.genesis.validators.len(), 1); + assert_ne!( + result.genesis.validators[0].address.as_bytes(), + [0; tendermint::account::LENGTH] + ); + assert_eq!(result.genesis.validators[0].power(), 10); + assert!(result.genesis.validators[0].pub_key.ed25519().is_some()); + assert_eq!(result.genesis.validators[0].proposer_priority.value(), 0); + assert_eq!(result.genesis.consensus_params.block.time_iota_ms, 500); + }, + "net_info" => { + let result = endpoint::net_info::Response::from_string(content).unwrap(); + assert_eq!(result.listeners.len(), 1); + assert_eq!(result.listeners[0].to_string(), "Listener(@)"); + assert!(result.listening); + assert_eq!(result.n_peers, 0); + assert!(result.peers.is_empty()); + }, + "status" => { + let result = endpoint::status::Response::from_string(content).unwrap(); + assert_eq!( + Address::from_listen_address(&result.node_info.listen_addr).unwrap(), + Address::from_str("tcp://0.0.0.0:26656").unwrap() + ); + assert_eq!(result.node_info.moniker.to_string(), "dockernode"); + assert_eq!(result.node_info.network.to_string(), CHAIN_ID); + assert_eq!( + result.node_info.other.rpc_address, + format!("{}", Address::from_str("tcp://0.0.0.0:26657").unwrap()) + ); + assert_eq!( + result.node_info.other.tx_index, + tendermint::node::info::TxIndexStatus::On + ); + assert_eq!( + result.node_info.protocol_version, + tendermint::node::info::ProtocolVersionInfo { + p2p: 8, + block: 11, + app: 1 + } + ); + assert_eq!(result.node_info.version.to_string(), "0.34.21"); + assert!(!result.sync_info.catching_up); + assert_eq!( + result.sync_info.latest_app_hash.as_bytes(), + [6, 0, 0, 0, 0, 0, 0, 0] + ); + assert!(!result.sync_info.latest_block_hash.is_empty()); + assert!( + result + .sync_info + .latest_block_time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(result.validator_info.pub_key.ed25519().is_some()); + assert_eq!(result.validator_info.power.value(), 10); + }, + "blockchain_from_1_to_10" => { + let result = endpoint::blockchain::Response::from_string(content).unwrap(); + assert_eq!(result.block_metas.len(), 10); + for block_meta in result.block_metas { + assert!(!block_meta.block_id.hash.is_empty()); + assert!(!block_meta.block_id.part_set_header.hash.is_empty()); + assert_eq!(block_meta.block_id.part_set_header.total, 1); + assert!(block_meta.block_size > 0); + if block_meta.header.height.value() == 1 { + assert!(block_meta.header.app_hash.as_bytes().is_empty()); + assert_eq!(block_meta.header.data_hash, empty_merkle_root_hash); + assert_eq!(block_meta.header.evidence_hash, empty_merkle_root_hash); + assert!(block_meta.header.last_block_id.is_none()); + assert_eq!(block_meta.header.last_commit_hash, empty_merkle_root_hash); + assert_eq!(block_meta.header.last_results_hash, empty_merkle_root_hash); + } else { + assert!(!block_meta.header.app_hash.as_bytes().is_empty()); + assert!(block_meta.header.data_hash.is_some()); + assert!(block_meta.header.evidence_hash.is_some()); + assert!(block_meta.header.last_block_id.is_some()); + assert!(block_meta.header.last_commit_hash.is_some()); + assert!(block_meta.header.last_results_hash.is_some()); + } + assert_eq!(block_meta.header.chain_id.as_str(), CHAIN_ID); + assert!(!block_meta.header.consensus_hash.is_empty()); + assert!(!block_meta.header.next_validators_hash.is_empty()); + assert_ne!( + block_meta.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + block_meta + .header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!block_meta.header.validators_hash.is_empty()); + assert_eq!( + block_meta.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + assert_eq!(block_meta.num_txs, 0); + } + }, + "subscribe_malformed" => { + let result = endpoint::subscribe::Response::from_string(content); + + match result { + Err(Error(ErrorDetail::Response(e), _)) => { + let response = e.source; + + assert_eq!(response.code(), Code::InternalError); + assert_eq!(response.message(), "Internal error"); + assert_eq!(response.data().unwrap(),"failed to parse query: \nparse error near PegText (line 1 symbol 2 - line 1 symbol 11):\n\"malformed\"\n"); + }, + _ => panic!("expected Response error"), + } + }, + "subscribe_newblock" => { + let result = endpoint::subscribe::Response::from_string(content); + + match result { + Err(Error(ErrorDetail::Serde(_), _)) => {}, + _ => panic!("expected Serde parse error, instead got {result:?}"), + } + }, + "subscribe_newblock_0" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + assert!(result_begin_block.unwrap().events.is_empty()); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_newblock_1" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + let rbb = result_begin_block.unwrap(); + assert_eq!(rbb.events.len(), 2); + assert_eq!(rbb.events[0].kind, "transfer"); + assert_eq!(rbb.events[0].attributes.len(), 2); + assert_eq!(rbb.events[0].attributes[0].key, "recipient"); + assert_eq!( + rbb.events[0].attributes[0].value, + "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta" + ); + assert!(rbb.events[0].attributes[0].index); + assert_eq!(rbb.events[0].attributes[1].key, "sender"); + assert_eq!( + rbb.events[0].attributes[1].value, + "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q" + ); + assert!(!rbb.events[0].attributes[1].index); + assert_eq!(rbb.events[1].kind, "message"); + assert_eq!(rbb.events[1].attributes.len(), 1); + assert_eq!(rbb.events[1].attributes[0].key, "sender"); + assert_eq!( + rbb.events[1].attributes[0].value, + "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q" + ); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_newblock_2" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + assert!(result_begin_block.unwrap().events.is_empty()); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_newblock_3" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + assert!(result_begin_block.unwrap().events.is_empty()); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_newblock_4" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + assert!(result_begin_block.unwrap().events.is_empty()); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_txs" => { + assert!(endpoint::subscribe::Response::from_string(content).is_ok()); + }, + "subscribe_txs_0" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 1); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx0"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHgwPXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + check_event_attrs(&result.events.unwrap(), "tx0", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_1" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 1); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx1"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHgxPXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + + check_event_attrs(&result.events.unwrap(), "tx1", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_2" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 1); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx2"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHgyPXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + check_event_attrs(&result.events.unwrap(), "tx2", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_3" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 1); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx3"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHgzPXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + check_event_attrs(&result.events.unwrap(), "tx3", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_4" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 1); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx4"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHg0PXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + check_event_attrs(&result.events.unwrap(), "tx4", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_broadcast_tx_0" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_1" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_2" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_3" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_4" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_5" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "tx" => { + let result: endpoint::tx::Response = + endpoint::tx::DialectResponse::::from_string(content) + .unwrap() + .into(); + assert_eq!( + result.hash, + Hash::from_bytes( + Algorithm::Sha256, + &[ + 214, 63, 156, 35, 121, 30, 97, 4, 16, 181, 118, 216, 194, 123, 181, + 174, 172, 147, 204, 26, 88, 82, 36, 40, 167, 179, 42, 18, 118, 8, 88, + 96 + ] + ) + .unwrap() + ); + assert_eq!(u64::from(result.height), 12u64); + }, + "tx_search_no_prove" => { + let result: endpoint::tx_search::Response = + endpoint::tx_search::DialectResponse::::from_string(content) + .unwrap() + .into(); + assert_eq!(result.total_count as usize, result.txs.len()); + // Test a few selected attributes of the results. + for tx in result.txs { + assert_ne!(tx.hash.as_bytes(), [0; 32]); + assert_eq!(tx.tx_result.code, abci::Code::Ok); + assert_eq!(tx.tx_result.events.len(), 1); + assert_eq!(tx.tx_result.events[0].kind, "app"); + assert_eq!(tx.tx_result.gas_used, 0); + assert_eq!(tx.tx_result.gas_wanted, 0); + assert!(tx.tx_result.info.to_string().is_empty()); + assert!(tx.tx_result.log.is_empty()); + assert!(tx.proof.is_none()); + } + }, + "tx_search_with_prove" => { + let result: endpoint::tx_search::Response = + endpoint::tx_search::DialectResponse::::from_string(content) + .unwrap() + .into(); + assert_eq!(result.total_count as usize, result.txs.len()); + // Test a few selected attributes of the results. + for tx in result.txs { + assert_ne!(tx.hash.as_bytes(), [0; 32]); + assert_eq!(tx.tx_result.code, abci::Code::Ok); + assert_eq!(tx.tx_result.events.len(), 1); + assert_eq!(tx.tx_result.events[0].kind, "app"); + assert_eq!(tx.tx_result.gas_used, 0); + assert_eq!(tx.tx_result.gas_wanted, 0); + assert!(tx.tx_result.info.to_string().is_empty()); + assert!(tx.tx_result.log.is_empty()); + let proof = tx.proof.unwrap(); + assert_eq!(proof.data, tx.tx); + assert_eq!(proof.proof.total, 1); + assert_eq!(proof.proof.index, 0); + assert_ne!(proof.root_hash.as_bytes(), [0; 32]); + } + }, + _ => { + panic!("cannot parse file name: {file_name}"); + }, + } + } +} + +fn check_event_attrs(events: &HashMap>, app_key: &str, height: i64) { + for (k, v) in events { + assert_eq!(v.len(), 1); + match k.as_str() { + "app.creator" => assert_eq!(v[0], "Cosmoshi Netowoko"), + "app.index_key" => assert_eq!(v[0], "index is working"), + "app.key" => assert_eq!(v[0], app_key), + "app.noindex_key" => assert_eq!(v[0], "index is working"), + "tm.event" => assert_eq!(v[0], "Tx"), + "tx.hash" => assert_eq!(v[0].len(), 64), + "tx.height" => assert_eq!(v[0], height.to_string()), + _ => panic!("unknown event found {k}"), + } + } +} diff --git a/rpc/tests/kvstore_fixtures/incoming/abci_info.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/abci_info.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/abci_info.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/abci_info.json diff --git a/rpc/tests/kvstore_fixtures/incoming/abci_query_with_existing_key.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/abci_query_with_existing_key.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/abci_query_with_existing_key.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/abci_query_with_existing_key.json diff --git a/rpc/tests/kvstore_fixtures/incoming/abci_query_with_non_existent_key.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/abci_query_with_non_existent_key.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/abci_query_with_non_existent_key.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/abci_query_with_non_existent_key.json diff --git a/rpc/tests/kvstore_fixtures/incoming/block_at_height_0.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/block_at_height_0.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/block_at_height_0.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/block_at_height_0.json diff --git a/rpc/tests/kvstore_fixtures/incoming/block_at_height_1.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/block_at_height_1.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/block_at_height_1.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/block_at_height_1.json diff --git a/rpc/tests/kvstore_fixtures/incoming/block_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/block_at_height_10.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/block_at_height_10.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/block_at_height_10.json diff --git a/rpc/tests/kvstore_fixtures/incoming/block_by_hash.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/block_by_hash.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/block_by_hash.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/block_by_hash.json diff --git a/rpc/tests/kvstore_fixtures/incoming/block_results_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/block_results_at_height_10.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/block_results_at_height_10.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/block_results_at_height_10.json diff --git a/rpc/tests/kvstore_fixtures/incoming/block_search.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/block_search.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/block_search.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/block_search.json diff --git a/rpc/tests/kvstore_fixtures/incoming/block_search_evidence.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/block_search_evidence.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/block_search_evidence.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/block_search_evidence.json diff --git a/rpc/tests/kvstore_fixtures/incoming/blockchain_from_1_to_10.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/blockchain_from_1_to_10.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/blockchain_from_1_to_10.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/blockchain_from_1_to_10.json diff --git a/rpc/tests/kvstore_fixtures/incoming/broadcast_tx_async.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/broadcast_tx_async.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/broadcast_tx_async.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/broadcast_tx_async.json diff --git a/rpc/tests/kvstore_fixtures/incoming/broadcast_tx_commit.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/broadcast_tx_commit.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/broadcast_tx_commit.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/broadcast_tx_commit.json diff --git a/rpc/tests/kvstore_fixtures/incoming/broadcast_tx_sync.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/broadcast_tx_sync.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/broadcast_tx_sync.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/broadcast_tx_sync.json diff --git a/rpc/tests/kvstore_fixtures/incoming/commit_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/commit_at_height_10.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/commit_at_height_10.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/commit_at_height_10.json diff --git a/rpc/tests/kvstore_fixtures/incoming/consensus_params.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/consensus_params.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/consensus_params.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/consensus_params.json diff --git a/rpc/tests/kvstore_fixtures/incoming/consensus_state.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/consensus_state.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/consensus_state.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/consensus_state.json diff --git a/rpc/tests/kvstore_fixtures/incoming/genesis.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/genesis.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/genesis.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/genesis.json diff --git a/rpc/tests/kvstore_fixtures/incoming/net_info.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/net_info.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/net_info.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/net_info.json diff --git a/rpc/tests/kvstore_fixtures/incoming/status.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/status.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/status.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/status.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_malformed.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_malformed.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_malformed.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_malformed.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_newblock.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_newblock.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_0.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_0.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_0.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_0.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_1.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_1.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_1.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_1.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_2.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_2.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_2.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_2.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_3.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_3.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_3.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_3.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_4.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_4.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_newblock_4.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_newblock_4.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_0.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_0.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_0.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_0.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_1.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_1.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_1.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_1.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_2.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_2.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_2.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_2.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_3.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_3.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_3.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_3.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_4.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_4.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_4.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_4.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_0.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_0.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_0.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_0.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_1.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_1.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_1.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_1.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_2.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_2.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_2.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_2.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_3.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_3.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_3.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_3.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_4.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_4.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_4.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_4.json diff --git a/rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_5.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_5.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/subscribe_txs_broadcast_tx_5.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/subscribe_txs_broadcast_tx_5.json diff --git a/rpc/tests/kvstore_fixtures/incoming/tx.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/tx.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/tx.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/tx.json diff --git a/rpc/tests/kvstore_fixtures/incoming/tx_search_no_prove.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/tx_search_no_prove.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/tx_search_no_prove.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/tx_search_no_prove.json diff --git a/rpc/tests/kvstore_fixtures/incoming/tx_search_with_prove.json b/rpc/tests/kvstore_fixtures/v0_34/incoming/tx_search_with_prove.json similarity index 100% rename from rpc/tests/kvstore_fixtures/incoming/tx_search_with_prove.json rename to rpc/tests/kvstore_fixtures/v0_34/incoming/tx_search_with_prove.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/abci_info.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/abci_info.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/abci_info.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/abci_info.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/abci_query_with_existing_key.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/abci_query_with_existing_key.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/abci_query_with_existing_key.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/abci_query_with_existing_key.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/abci_query_with_non_existent_key.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/abci_query_with_non_existent_key.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/abci_query_with_non_existent_key.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/abci_query_with_non_existent_key.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/block_at_height_0.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/block_at_height_0.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/block_at_height_0.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/block_at_height_0.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/block_at_height_1.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/block_at_height_1.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/block_at_height_1.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/block_at_height_1.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/block_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/block_at_height_10.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/block_at_height_10.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/block_at_height_10.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/block_by_hash.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/block_by_hash.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/block_by_hash.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/block_by_hash.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/block_results_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/block_results_at_height_10.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/block_results_at_height_10.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/block_results_at_height_10.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/block_search.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/block_search.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/block_search.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/block_search.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/blockchain_from_1_to_10.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/blockchain_from_1_to_10.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/blockchain_from_1_to_10.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/blockchain_from_1_to_10.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/broadcast_tx_async.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/broadcast_tx_async.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/broadcast_tx_async.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/broadcast_tx_async.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/broadcast_tx_commit.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/broadcast_tx_commit.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/broadcast_tx_commit.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/broadcast_tx_commit.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/broadcast_tx_sync.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/broadcast_tx_sync.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/broadcast_tx_sync.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/broadcast_tx_sync.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/commit_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/commit_at_height_10.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/commit_at_height_10.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/commit_at_height_10.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/consensus_params.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/consensus_params.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/consensus_params.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/consensus_params.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/consensus_state.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/consensus_state.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/consensus_state.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/consensus_state.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/genesis.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/genesis.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/genesis.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/genesis.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/net_info.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/net_info.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/net_info.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/net_info.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/status.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/status.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/status.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/status.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/subscribe_malformed.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_malformed.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/subscribe_malformed.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_malformed.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/subscribe_newblock.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_newblock.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/subscribe_newblock.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_newblock.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/subscribe_txs.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/subscribe_txs.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_0.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_0.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_0.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_0.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_1.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_1.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_1.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_1.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_2.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_2.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_2.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_2.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_3.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_3.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_3.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_3.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_4.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_4.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_4.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_4.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_5.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_5.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/subscribe_txs_broadcast_tx_5.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/subscribe_txs_broadcast_tx_5.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/tx.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/tx.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/tx.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/tx.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/tx_search_no_prove.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/tx_search_no_prove.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/tx_search_no_prove.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/tx_search_no_prove.json diff --git a/rpc/tests/kvstore_fixtures/outgoing/tx_search_with_prove.json b/rpc/tests/kvstore_fixtures/v0_34/outgoing/tx_search_with_prove.json similarity index 100% rename from rpc/tests/kvstore_fixtures/outgoing/tx_search_with_prove.json rename to rpc/tests/kvstore_fixtures/v0_34/outgoing/tx_search_with_prove.json diff --git a/rpc/tests/kvstore_fixtures/v0_37.rs b/rpc/tests/kvstore_fixtures/v0_37.rs new file mode 100644 index 000000000..9d2fa3550 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37.rs @@ -0,0 +1,1431 @@ +use super::*; + +#[test] +fn outgoing_fixtures() { + for json_file in find_fixtures("v0_37", "outgoing") { + let file_name = json_file + .file_name() + .unwrap() + .to_str() + .unwrap() + .strip_suffix(".json") + .unwrap(); + let content = fs::read_to_string(&json_file).unwrap(); + match file_name { + "abci_info" => assert!(serde_json::from_str::< + RequestWrapper, + >(&content) + .is_ok()), + "abci_query_with_existing_key" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert!(wrapped.params().path.is_none()); + assert_eq!(wrapped.params().data, hex::decode("747830").unwrap()); + assert!(wrapped.params().height.is_none()); + assert!(!wrapped.params().prove); + }, + "abci_query_with_non_existent_key" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert!(wrapped.params().path.is_none()); + assert_eq!( + wrapped.params().data, + hex::decode("6e6f6e5f6578697374656e745f6b6579").unwrap() + ); + assert!(wrapped.params().height.is_none()); + assert!(!wrapped.params().prove); + }, + "block_at_height_0" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 0); + }, + "block_at_height_1" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 1); + }, + "block_at_height_10" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 10); + }, + "block_by_hash" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!( + wrapped.params().hash.unwrap().to_string(), + "FCF9C2537FC3534CA71001FE1F14C4F769090948C1A521682F612E7CF73AE639" + ); + }, + "block_results_at_height_10" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 10); + }, + "block_search" => { + let wrapped = + serde_json::from_str::>( + &content, + ) + .unwrap(); + assert_eq!(wrapped.params().query, "block.height > 1"); + assert_eq!(wrapped.params().page, 1); + assert_eq!(wrapped.params().per_page, 100); + assert_eq!(wrapped.params().order_by, Order::Ascending); + }, + "blockchain_from_1_to_10" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().min_height.value(), 1); + assert_eq!(wrapped.params().max_height.value(), 10); + }, + "broadcast_tx_async" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!( + wrapped.params().tx, + base64::decode("YXN5bmMta2V5PXZhbHVl").unwrap() + ); + }, + "broadcast_tx_commit" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!( + wrapped.params().tx, + base64::decode("Y29tbWl0LWtleT12YWx1ZQ==").unwrap() + ); + }, + "broadcast_tx_sync" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!( + wrapped.params().tx, + base64::decode("c3luYy1rZXk9dmFsdWU=").unwrap() + ); + }, + "commit_at_height_10" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().height.unwrap().value(), 10); + }, + "consensus_params" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + let height = wrapped.params().height.unwrap(); + assert_eq!(u64::from(height), 10u64); + }, + "consensus_state" => assert!(serde_json::from_str::< + RequestWrapper, + >(&content) + .is_ok()), + "genesis" => assert!(serde_json::from_str::< + RequestWrapper>, + >(&content) + .is_ok()), + "net_info" => assert!(serde_json::from_str::< + RequestWrapper, + >(&content) + .is_ok()), + "status" => assert!( + serde_json::from_str::>(&content).is_ok() + ), + "subscribe_malformed" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "malformed query"); + }, + "subscribe_newblock" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "tm.event = 'NewBlock'"); + }, + "subscribe_txs" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "tm.event = 'Tx'"); + }, + "subscribe_txs_broadcast_tx_0" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHgwPXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_1" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHgxPXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_2" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHgyPXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_3" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHgzPXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_4" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHg0PXZhbHVl").unwrap()); + }, + "subscribe_txs_broadcast_tx_5" => { + let wrapped = serde_json::from_str::< + RequestWrapper, + >(&content) + .unwrap(); + assert_eq!(wrapped.params().tx, base64::decode("dHg1PXZhbHVl").unwrap()); + }, + "tx" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!( + wrapped.params().hash, + Hash::from_bytes( + Algorithm::Sha256, + &[ + 214, 63, 156, 35, 121, 30, 97, 4, 16, 181, 118, 216, 194, 123, 181, + 174, 172, 147, 204, 26, 88, 82, 36, 40, 167, 179, 42, 18, 118, 8, 88, + 96 + ] + ) + .unwrap() + ); + assert!(!wrapped.params().prove); + }, + "tx_search_no_prove" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "tx.height > 1"); + assert!(!wrapped.params().prove); + assert_eq!(wrapped.params().page, 1); + assert_eq!(wrapped.params().per_page, 10); + assert_eq!(wrapped.params().order_by, Order::Ascending); + }, + "tx_search_with_prove" => { + let wrapped = + serde_json::from_str::>(&content) + .unwrap(); + assert_eq!(wrapped.params().query, "tx.height > 1"); + assert!(wrapped.params().prove); + assert_eq!(wrapped.params().page, 1); + assert_eq!(wrapped.params().per_page, 10); + assert_eq!(wrapped.params().order_by, Order::Ascending); + }, + _ => { + panic!("cannot parse file name: {file_name}"); + }, + } + } +} + +#[test] +fn incoming_fixtures() { + use tendermint_rpc::dialect::v0_37::Event as RpcEvent; + + let empty_merkle_root_hash = Some( + tendermint::Hash::from_hex_upper( + tendermint::hash::Algorithm::Sha256, + "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + ) + .unwrap(), + ); + let informal_epoch = + tendermint::Time::parse_from_rfc3339("2020-01-01T00:00:00.000000000Z").unwrap(); + + for json_file in find_fixtures("v0_37", "incoming") { + let file_name = json_file + .file_name() + .unwrap() + .to_str() + .unwrap() + .strip_suffix(".json") + .unwrap(); + let content = fs::read_to_string(&json_file).unwrap(); + match file_name { + "abci_info" => { + let result = endpoint::abci_info::Response::from_string(content).unwrap(); + assert_eq!(result.response.app_version, 1); + assert_eq!(result.response.data, "{\"size\":9}"); + assert_eq!( + result.response.last_block_app_hash.as_bytes(), + b"EgAAAAAAAAA=" + ); + assert_eq!(result.response.version, "1.0.0"); + }, + "abci_query_with_existing_key" => { + let result = endpoint::abci_query::Response::from_string(content).unwrap(); + assert_eq!(result.response.code.value(), 0); + assert!(result.response.codespace.is_empty()); + assert_eq!(result.response.index, 0); + assert!(result.response.info.is_empty()); + assert_eq!(result.response.key, base64::decode("dHgw").unwrap()); + assert_eq!(result.response.log, "exists"); + assert!(result.response.proof.is_none()); + assert_eq!(result.response.value, base64::decode("dmFsdWU=").unwrap()); + }, + "abci_query_with_non_existent_key" => { + let result = endpoint::abci_query::Response::from_string(content).unwrap(); + assert_eq!(result.response.code.value(), 0); + assert!(result.response.codespace.is_empty()); + assert_eq!(result.response.index, 0); + assert!(result.response.info.is_empty()); + assert_eq!( + result.response.key, + base64::decode("bm9uX2V4aXN0ZW50X2tleQ==").unwrap() + ); + assert_eq!(result.response.log, "does not exist"); + assert!(result.response.proof.is_none()); + assert!(result.response.value.is_empty()); + }, + "block_at_height_0" => { + let res = endpoint::block::Response::from_string(&content); + + match res { + Err(Error(ErrorDetail::Response(e), _)) => { + let response = e.source; + assert_eq!(response.code(), Code::InternalError); + assert_eq!(response.message(), "Internal error"); + assert_eq!( + response.data(), + Some("height must be greater than 0, but got 0") + ); + }, + _ => panic!("expected Response error"), + } + }, + "block_at_height_1" => { + let result = endpoint::block::Response::from_string(content).unwrap(); + assert!(result.block.data.get(0).is_none()); + assert!(result.block.evidence.iter().next().is_none()); + assert!(result.block.header.app_hash.as_bytes().is_empty()); + assert_eq!(result.block.header.chain_id.as_str(), CHAIN_ID); + assert!(!result.block.header.consensus_hash.is_empty()); + assert_eq!(result.block.header.data_hash, empty_merkle_root_hash); + assert_eq!(result.block.header.evidence_hash, empty_merkle_root_hash); + assert_eq!(result.block.header.height.value(), 1); + assert!(result.block.header.last_block_id.is_none()); + assert_eq!(result.block.header.last_commit_hash, empty_merkle_root_hash); + assert_eq!( + result.block.header.last_results_hash, + empty_merkle_root_hash + ); + assert!(!result.block.header.next_validators_hash.is_empty()); + assert_ne!( + result.block.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + result + .block + .header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!result.block.header.validators_hash.is_empty()); + assert_eq!( + result.block.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + assert!(result.block.last_commit.is_none()); + assert!(!result.block_id.hash.is_empty()); + assert!(!result.block_id.part_set_header.hash.is_empty()); + assert_eq!(result.block_id.part_set_header.total, 1); + }, + "block_at_height_10" => { + let result = endpoint::block::Response::from_string(content).unwrap(); + assert!(result.block.data.get(0).is_none()); + assert!(result.block.evidence.iter().next().is_none()); + assert_eq!(result.block.header.app_hash.as_bytes(), &[0u8; 8]); + assert_eq!(result.block.header.chain_id.as_str(), CHAIN_ID); + assert!(!result.block.header.consensus_hash.is_empty()); + assert_eq!(result.block.header.data_hash, empty_merkle_root_hash); + assert_eq!(result.block.header.evidence_hash, empty_merkle_root_hash); + assert_eq!(result.block.header.height.value(), 10); + assert!(result.block.header.last_block_id.is_some()); + assert!(result.block.header.last_commit_hash.is_some()); + assert!(result.block.header.last_results_hash.is_some()); + assert!(!result.block.header.next_validators_hash.is_empty()); + assert_ne!( + result.block.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + result + .block + .header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!result.block.header.validators_hash.is_empty()); + assert_eq!( + result.block.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = result.block.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.height.value(), 9); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + // It's weird but there is no implementation to get the signature out of CommitSig. + assert!(!result.block_id.hash.is_empty()); + assert!(!result.block_id.part_set_header.hash.is_empty()); + assert_eq!(result.block_id.part_set_header.total, 1); + }, + "block_results_at_height_10" => { + let result: endpoint::block_results::Response = + endpoint::block_results::DialectResponse::::from_string(content) + .unwrap() + .into(); + assert!(result.begin_block_events.is_none()); + assert!(result.consensus_param_updates.is_none()); + assert!(result.end_block_events.is_none()); + assert_eq!(result.height.value(), 10); + assert!(result.txs_results.is_none()); + assert!(result.validator_updates.is_empty()); + }, + "block_by_hash" => { + let result = endpoint::block_by_hash::Response::from_string(content).unwrap(); + assert_eq!( + result.block_id.hash.to_string(), + "FCF9C2537FC3534CA71001FE1F14C4F769090948C1A521682F612E7CF73AE639" + ); + }, + "block_search" => { + let result = endpoint::block_search::Response::from_string(content).unwrap(); + assert_eq!(result.total_count as usize, result.blocks.len()); + for response in result.blocks { + assert!(response.block.header.height.value() > 1); + } + }, + "block_search_evidence" => { + let result = endpoint::block_search::Response::from_string(content).unwrap(); + assert_eq!(result.total_count as usize, result.blocks.len()); + + // Test a few selected attributes of the results. + for block in result.blocks { + let evidence = block.block.evidence.iter().next().unwrap(); + + use tendermint::vote; + + fn check_vote(vote: &Vote) { + assert_eq!(vote.vote_type, vote::Type::Precommit); + assert_eq!(vote.height.value(), 8009); + assert_eq!(vote.round.value(), 0); + assert_eq!( + vote.validator_address, + "9319035301DA526CC78DCF174A47A74F81401291".parse().unwrap(), + ); + assert_eq!(vote.validator_index.value(), 8); + } + + if let Evidence::DuplicateVote(dup) = evidence { + assert_eq!(dup.total_voting_power.value(), 121); + assert_eq!(dup.validator_power.value(), 1); + assert_eq!( + dup.timestamp, + "2022-09-12T19:49:49.984608464Z".parse().unwrap() + ); + + check_vote(&dup.vote_a); + check_vote(&dup.vote_b); + } else { + panic!("not a duplicate vote: {evidence:?}"); + } + } + }, + "broadcast_tx_async" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "broadcast_tx_commit" => { + let result: endpoint::broadcast::tx_commit::Response = + endpoint::broadcast::tx_commit::DialectResponse::::from_string( + content, + ) + .unwrap() + .into(); + assert_eq!(result.check_tx.code, abci::Code::Ok); + assert!(result.check_tx.codespace.is_empty()); + assert!(result.check_tx.data.is_empty()); + assert!(result.check_tx.events.is_empty()); + assert_eq!(result.check_tx.gas_used, 0); + // Todo: https://github.com/informalsystems/tendermint-rs/issues/761 + // assert_eq!(result.check_tx.gas_wanted.value(), 1); + assert!(result.check_tx.info.to_string().is_empty()); + assert!(result.check_tx.log.is_empty()); + assert_eq!(result.deliver_tx.code, abci::Code::Ok); + assert!(result.deliver_tx.codespace.is_empty()); + assert!(result.deliver_tx.data.is_empty()); + assert_eq!(result.deliver_tx.events.len(), 2); + assert_eq!(result.deliver_tx.events[0].attributes.len(), 4); + assert_eq!(result.deliver_tx.events[0].attributes[0].key, "creator"); + assert_eq!( + result.deliver_tx.events[0].attributes[0].value, + "Cosmoshi Netowoko" + ); + assert_eq!(result.deliver_tx.events[0].attributes[1].key, "key"); + assert_eq!( + result.deliver_tx.events[0].attributes[1].value, + "commit-key" + ); + assert_eq!(result.deliver_tx.events[0].attributes[2].key, "index_key"); + assert_eq!( + result.deliver_tx.events[0].attributes[2].value, + "index is working" + ); + assert_eq!(result.deliver_tx.events[0].attributes[3].key, "noindex_key"); + assert_eq!( + result.deliver_tx.events[0].attributes[3].value, + "index is working" + ); + assert_eq!(result.deliver_tx.events[0].kind, "app"); + assert_eq!(result.deliver_tx.gas_used, 0); + assert_eq!(result.deliver_tx.gas_wanted, 0); + assert!(result.deliver_tx.info.to_string().is_empty()); + assert!(result.deliver_tx.log.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + }, + "broadcast_tx_sync" => { + let result = endpoint::broadcast::tx_sync::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "commit_at_height_10" => { + let result = endpoint::commit::Response::from_string(content).unwrap(); + assert!(!result.signed_header.commit.block_id.hash.is_empty()); + assert_eq!(result.signed_header.commit.height.value(), 10); + assert_eq!(result.signed_header.commit.round.value(), 0); + assert_eq!(result.signed_header.commit.signatures.len(), 1); + assert!(result.signed_header.commit.signatures[0].is_commit()); + assert!(result.signed_header.commit.signatures[0] + .validator_address() + .is_some()); + assert_eq!(result.signed_header.header.app_hash.as_bytes(), [0u8; 8]); + assert_eq!(result.signed_header.header.chain_id.as_str(), CHAIN_ID); + assert!(!result.signed_header.header.consensus_hash.is_empty()); + assert_eq!( + result.signed_header.header.data_hash, + empty_merkle_root_hash + ); + assert_eq!( + result.signed_header.header.evidence_hash, + empty_merkle_root_hash + ); + assert_eq!(result.signed_header.header.height.value(), 10); + assert!(result.signed_header.header.last_block_id.is_some()); + assert!(result.signed_header.header.last_commit_hash.is_some()); + assert!(result.signed_header.header.last_results_hash.is_some()); + assert!(!result.signed_header.header.next_validators_hash.is_empty()); + assert_ne!( + result.signed_header.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + result + .signed_header + .header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!result.signed_header.header.validators_hash.is_empty()); + assert_eq!( + result.signed_header.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + }, + "consensus_params" => { + let result = endpoint::consensus_params::Response::from_string(content).unwrap(); + assert_eq!(u64::from(result.block_height), 10_u64); + assert_eq!(result.consensus_params.block.max_bytes, 22020096_u64); + assert_eq!(result.consensus_params.block.max_gas, -1_i64); + assert_eq!(result.consensus_params.block.time_iota_ms, 1000_i64); + assert_eq!( + result.consensus_params.evidence.max_age_duration, + Duration(core::time::Duration::from_nanos(172800000000000_u64)) + ); + assert_eq!( + result.consensus_params.evidence.max_age_num_blocks, + 100000_u64 + ); + assert_eq!(result.consensus_params.evidence.max_bytes, 1048576_i64); + assert_eq!( + result.consensus_params.validator.pub_key_types, + vec![public_key::Algorithm::Ed25519] + ); + }, + "consensus_state" => { + assert!(endpoint::consensus_state::Response::from_string(content).is_ok()); + }, + "genesis" => { + let result = + endpoint::genesis::Response::>::from_string(content) + .unwrap(); + assert!(result.genesis.app_hash.as_bytes().is_empty()); + assert_eq!(result.genesis.chain_id.as_str(), CHAIN_ID); + assert_eq!(result.genesis.consensus_params.block.max_bytes, 22020096); + assert_eq!(result.genesis.consensus_params.block.max_gas, -1); + assert_eq!( + result + .genesis + .consensus_params + .evidence + .max_age_duration + .0 + .as_nanos(), + 172800000000000 + ); + assert_eq!( + result.genesis.consensus_params.evidence.max_age_num_blocks, + 100000 + ); + assert_eq!(result.genesis.consensus_params.evidence.max_bytes, 1048576); + assert_eq!( + result + .genesis + .consensus_params + .validator + .pub_key_types + .len(), + 1 + ); + assert_eq!( + result.genesis.consensus_params.validator.pub_key_types[0], + tendermint::public_key::Algorithm::Ed25519 + ); + assert!(result.genesis.consensus_params.version.is_none()); + assert!( + result + .genesis + .genesis_time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert_eq!(result.genesis.validators.len(), 1); + assert_ne!( + result.genesis.validators[0].address.as_bytes(), + [0; tendermint::account::LENGTH] + ); + assert_eq!(result.genesis.validators[0].power(), 10); + assert!(result.genesis.validators[0].pub_key.ed25519().is_some()); + assert_eq!(result.genesis.validators[0].proposer_priority.value(), 0); + assert_eq!(result.genesis.consensus_params.block.time_iota_ms, 1000); + }, + "net_info" => { + let result = endpoint::net_info::Response::from_string(content).unwrap(); + assert_eq!(result.listeners.len(), 1); + assert_eq!(result.listeners[0].to_string(), "Listener(@)"); + assert!(result.listening); + assert_eq!(result.n_peers, 0); + assert!(result.peers.is_empty()); + }, + "status" => { + let result = endpoint::status::Response::from_string(content).unwrap(); + assert_eq!( + Address::from_listen_address(&result.node_info.listen_addr).unwrap(), + Address::from_str("tcp://0.0.0.0:26656").unwrap() + ); + assert_eq!(result.node_info.moniker.to_string(), "dockernode"); + assert_eq!(result.node_info.network.to_string(), CHAIN_ID); + assert_eq!( + result.node_info.other.rpc_address, + format!("{}", Address::from_str("tcp://0.0.0.0:26657").unwrap()) + ); + assert_eq!( + result.node_info.other.tx_index, + tendermint::node::info::TxIndexStatus::On + ); + assert_eq!( + result.node_info.protocol_version, + tendermint::node::info::ProtocolVersionInfo { + p2p: 8, + block: 11, + app: 1 + } + ); + assert_eq!(result.node_info.version.to_string(), "0.37.0-alpha.3"); + assert!(!result.sync_info.catching_up); + assert_eq!( + result.sync_info.latest_app_hash.as_bytes(), + [6, 0, 0, 0, 0, 0, 0, 0] + ); + assert!(!result.sync_info.latest_block_hash.is_empty()); + assert!( + result + .sync_info + .latest_block_time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(result.validator_info.pub_key.ed25519().is_some()); + assert_eq!(result.validator_info.power.value(), 10); + }, + "blockchain_from_1_to_10" => { + let result = endpoint::blockchain::Response::from_string(content).unwrap(); + assert_eq!(result.block_metas.len(), 10); + for block_meta in result.block_metas { + assert!(!block_meta.block_id.hash.is_empty()); + assert!(!block_meta.block_id.part_set_header.hash.is_empty()); + assert_eq!(block_meta.block_id.part_set_header.total, 1); + assert!(block_meta.block_size > 0); + if block_meta.header.height.value() == 1 { + assert!(block_meta.header.app_hash.as_bytes().is_empty()); + assert_eq!(block_meta.header.data_hash, empty_merkle_root_hash); + assert_eq!(block_meta.header.evidence_hash, empty_merkle_root_hash); + assert!(block_meta.header.last_block_id.is_none()); + assert_eq!(block_meta.header.last_commit_hash, empty_merkle_root_hash); + assert_eq!(block_meta.header.last_results_hash, empty_merkle_root_hash); + } else { + assert!(!block_meta.header.app_hash.as_bytes().is_empty()); + assert!(block_meta.header.data_hash.is_some()); + assert!(block_meta.header.evidence_hash.is_some()); + assert!(block_meta.header.last_block_id.is_some()); + assert!(block_meta.header.last_commit_hash.is_some()); + assert!(block_meta.header.last_results_hash.is_some()); + } + assert_eq!(block_meta.header.chain_id.as_str(), CHAIN_ID); + assert!(!block_meta.header.consensus_hash.is_empty()); + assert!(!block_meta.header.next_validators_hash.is_empty()); + assert_ne!( + block_meta.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + block_meta + .header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!block_meta.header.validators_hash.is_empty()); + assert_eq!( + block_meta.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + assert_eq!(block_meta.num_txs, 0); + } + }, + "subscribe_malformed" => { + let result = endpoint::subscribe::Response::from_string(content); + + match result { + Err(Error(ErrorDetail::Response(e), _)) => { + let response = e.source; + + assert_eq!(response.code(), Code::InternalError); + assert_eq!(response.message(), "Internal error"); + assert_eq!(response.data().unwrap(),"failed to parse query: \nparse error near PegText (line 1 symbol 2 - line 1 symbol 11):\n\"malformed\"\n"); + }, + _ => panic!("expected Response error"), + } + }, + "subscribe_newblock" => { + let result = endpoint::subscribe::Response::from_string(content); + + match result { + Err(Error(ErrorDetail::Serde(_), _)) => {}, + _ => panic!("expected Serde parse error, instead got {result:?}"), + } + }, + "subscribe_newblock_0" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + assert!(result_begin_block.unwrap().events.is_empty()); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_newblock_1" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + let rbb = result_begin_block.unwrap(); + assert_eq!(rbb.events.len(), 2); + assert_eq!(rbb.events[0].kind, "transfer"); + assert_eq!(rbb.events[0].attributes.len(), 2); + assert_eq!(rbb.events[0].attributes[0].key, "recipient"); + assert_eq!( + rbb.events[0].attributes[0].value, + "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta" + ); + assert!(rbb.events[0].attributes[0].index); + assert_eq!(rbb.events[0].attributes[1].key, "sender"); + assert_eq!( + rbb.events[0].attributes[1].value, + "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q" + ); + assert!(!rbb.events[0].attributes[1].index); + assert_eq!(rbb.events[1].kind, "message"); + assert_eq!(rbb.events[1].attributes.len(), 1); + assert_eq!(rbb.events[1].attributes[0].key, "sender"); + assert_eq!( + rbb.events[1].attributes[0].value, + "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q" + ); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_newblock_2" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + assert!(result_begin_block.unwrap().events.is_empty()); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_newblock_3" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + assert!(result_begin_block.unwrap().events.is_empty()); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_newblock_4" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + if let tendermint_rpc::event::EventData::NewBlock { + block, + result_begin_block, + result_end_block, + } = result.data.into() + { + let b = block.unwrap(); + assert!(b.data.get(0).is_none()); + assert!(b.evidence.iter().next().is_none()); + assert!(!b.header.app_hash.as_bytes().is_empty()); + assert_eq!(b.header.chain_id.as_str(), CHAIN_ID); + assert!(!b.header.consensus_hash.is_empty()); + assert_eq!(b.header.data_hash, empty_merkle_root_hash); + assert_eq!(b.header.evidence_hash, empty_merkle_root_hash); + assert!(b.header.last_block_id.is_some()); + assert!(b.header.last_commit_hash.is_some()); + assert!(b.header.last_results_hash.is_some()); + assert!(!b.header.next_validators_hash.is_empty()); + assert_ne!( + b.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + b.header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!b.header.validators_hash.is_empty()); + assert_eq!( + b.header.version, + tendermint::block::header::Version { block: 11, app: 1 } + ); + let last_commit = b.last_commit.unwrap(); + assert!(!last_commit.block_id.hash.is_empty()); + assert!(!last_commit.block_id.part_set_header.hash.is_empty()); + assert_eq!(last_commit.block_id.part_set_header.total, 1); + assert_eq!(last_commit.round.value(), 0); + assert_eq!(last_commit.signatures.len(), 1); + assert!(last_commit.signatures[0].is_commit()); + assert!(last_commit.signatures[0].validator_address().is_some()); + assert!(result_begin_block.unwrap().events.is_empty()); + let reb = result_end_block.unwrap(); + assert!(reb.validator_updates.is_empty()); + assert!(reb.consensus_param_updates.is_none()); + assert!(reb.events.is_empty()); + } else { + panic!("not a newblock"); + } + assert_eq!(result.query, "tm.event = 'NewBlock'"); + }, + "subscribe_txs" => { + assert!(endpoint::subscribe::Response::from_string(content).is_ok()); + }, + "subscribe_txs_0" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 2); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx0"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHgwPXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + check_event_attrs(&result.events.unwrap(), "tx0", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_1" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 2); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx1"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHgxPXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + + check_event_attrs(&result.events.unwrap(), "tx1", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_2" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 2); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx2"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHgyPXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + check_event_attrs(&result.events.unwrap(), "tx2", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_3" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 2); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx3"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHgzPXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + check_event_attrs(&result.events.unwrap(), "tx3", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_4" => { + let result = + tendermint_rpc::event::DialectEvent::::from_string(content).unwrap(); + let height; + if let tendermint_rpc::event::EventData::Tx { tx_result } = result.data.into() { + height = tx_result.height; + assert!(tx_result.result.log.is_none()); + assert!(tx_result.result.gas_wanted.is_none()); + assert!(tx_result.result.gas_used.is_none()); + assert_eq!(tx_result.result.events.len(), 2); + assert_eq!(tx_result.result.events[0].kind, "app"); + for attr in &tx_result.result.events[0].attributes { + match attr.key.as_str() { + "creator" => { + assert_eq!(attr.value, "Cosmoshi Netowoko") + }, + "key" => assert_eq!(attr.value, "tx4"), + "index_key" => { + assert_eq!(attr.value, "index is working") + }, + "noindex_key" => { + assert_eq!(attr.value, "index is working") + }, + _ => panic!("unknown attribute found {}", attr.key), + } + } + assert_eq!(tx_result.tx, base64::decode("dHg0PXZhbHVl").unwrap()); + } else { + panic!("not a tx"); + } + check_event_attrs(&result.events.unwrap(), "tx4", height); + assert_eq!(result.query, "tm.event = 'Tx'"); + }, + "subscribe_txs_broadcast_tx_0" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_1" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_2" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_3" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_4" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "subscribe_txs_broadcast_tx_5" => { + let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); + assert_eq!(result.code, abci::Code::Ok); + assert!(result.data.is_empty()); + assert_ne!( + result.hash, + Hash::from_bytes(Algorithm::Sha256, &[0; 32]).unwrap() + ); + assert!(result.log.is_empty()); + }, + "tx" => { + let result: endpoint::tx::Response = + endpoint::tx::DialectResponse::::from_string(content) + .unwrap() + .into(); + assert_eq!( + result.hash, + Hash::from_bytes( + Algorithm::Sha256, + &[ + 214, 63, 156, 35, 121, 30, 97, 4, 16, 181, 118, 216, 194, 123, 181, + 174, 172, 147, 204, 26, 88, 82, 36, 40, 167, 179, 42, 18, 118, 8, 88, + 96 + ] + ) + .unwrap() + ); + assert_eq!(u64::from(result.height), 12u64); + }, + "tx_search_no_prove" => { + let result: endpoint::tx_search::Response = + endpoint::tx_search::DialectResponse::::from_string(content) + .unwrap() + .into(); + assert_eq!(result.total_count as usize, result.txs.len()); + // Test a few selected attributes of the results. + for tx in result.txs { + assert_ne!(tx.hash.as_bytes(), [0; 32]); + assert_eq!(tx.tx_result.code, abci::Code::Ok); + assert_eq!(tx.tx_result.events.len(), 2); + assert_eq!(tx.tx_result.events[0].kind, "app"); + assert_eq!(tx.tx_result.gas_used, 0); + assert_eq!(tx.tx_result.gas_wanted, 0); + assert!(tx.tx_result.info.to_string().is_empty()); + assert!(tx.tx_result.log.is_empty()); + assert!(tx.proof.is_none()); + } + }, + "tx_search_with_prove" => { + let result: endpoint::tx_search::Response = + endpoint::tx_search::DialectResponse::::from_string(content) + .unwrap() + .into(); + assert_eq!(result.total_count as usize, result.txs.len()); + // Test a few selected attributes of the results. + for tx in result.txs { + assert_ne!(tx.hash.as_bytes(), [0; 32]); + assert_eq!(tx.tx_result.code, abci::Code::Ok); + assert_eq!(tx.tx_result.events.len(), 2); + assert_eq!(tx.tx_result.events[0].kind, "app"); + assert_eq!(tx.tx_result.gas_used, 0); + assert_eq!(tx.tx_result.gas_wanted, 0); + assert!(tx.tx_result.info.to_string().is_empty()); + assert!(tx.tx_result.log.is_empty()); + let proof = tx.proof.unwrap(); + assert_eq!(proof.data, tx.tx); + assert_eq!(proof.proof.total, 1); + assert_eq!(proof.proof.index, 0); + assert_ne!(proof.root_hash.as_bytes(), [0; 32]); + } + }, + _ => { + panic!("cannot parse file name: {file_name}"); + }, + } + } +} + +fn check_event_attrs(events: &HashMap>, app_key: &str, height: i64) { + for (k, v) in events { + match k.as_str() { + "app.creator" => { + assert_eq!(v.len(), 2); + assert_eq!(v[0], "Cosmoshi Netowoko"); + }, + "app.index_key" => { + assert_eq!(v.len(), 2); + assert_eq!(v[0], "index is working"); + }, + "app.key" => { + assert_eq!(v.len(), 2); + assert_eq!(v[0], app_key); + }, + "app.noindex_key" => { + assert_eq!(v.len(), 2); + assert_eq!(v[0], "index is working"); + }, + "tm.event" => { + assert_eq!(v.len(), 1); + assert_eq!(v[0], "Tx"); + }, + "tx.hash" => { + assert_eq!(v.len(), 1); + assert_eq!(v[0].len(), 64); + }, + "tx.height" => { + assert_eq!(v.len(), 1); + assert_eq!(v[0], height.to_string()); + }, + _ => panic!("unknown event found {k}"), + } + } +} diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/abci_info.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/abci_info.json new file mode 100644 index 000000000..303d67f9d --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/abci_info.json @@ -0,0 +1,13 @@ +{ + "id": "4e158c90-577c-4408-b8f6-d3680b84e7e9", + "jsonrpc": "2.0", + "result": { + "response": { + "app_version": "1", + "data": "{\"size\":9}", + "last_block_app_hash": "EgAAAAAAAAA=", + "last_block_height": "161", + "version": "1.0.0" + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/abci_query_with_existing_key.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/abci_query_with_existing_key.json new file mode 100644 index 000000000..63dc552bd --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/abci_query_with_existing_key.json @@ -0,0 +1,17 @@ +{ + "id": "4c088a2c-e01c-4d8b-aadc-009753b68d04", + "jsonrpc": "2.0", + "result": { + "response": { + "code": 0, + "codespace": "", + "height": "75", + "index": "0", + "info": "", + "key": "dHgw", + "log": "exists", + "proofOps": null, + "value": "dmFsdWU=" + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/abci_query_with_non_existent_key.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/abci_query_with_non_existent_key.json new file mode 100644 index 000000000..dde08d830 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/abci_query_with_non_existent_key.json @@ -0,0 +1,17 @@ +{ + "id": "437f6c65-b4b2-4417-9e03-2b584a75403f", + "jsonrpc": "2.0", + "result": { + "response": { + "code": 0, + "codespace": "", + "height": "163", + "index": "0", + "info": "", + "key": "bm9uX2V4aXN0ZW50X2tleQ==", + "log": "does not exist", + "proofOps": null, + "value": null + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/block_at_height_0.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_at_height_0.json new file mode 100644 index 000000000..fb69121fd --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_at_height_0.json @@ -0,0 +1,9 @@ +{ + "error": { + "code": -32603, + "data": "height must be greater than 0, but got 0", + "message": "Internal error" + }, + "id": "c1144ac0-8c4d-46cc-9430-8c14c598a029", + "jsonrpc": "2.0" +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/block_at_height_1.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_at_height_1.json new file mode 100644 index 000000000..056d76ab7 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_at_height_1.json @@ -0,0 +1,58 @@ +{ + "id": "5f66ff6f-8283-4c9a-8437-b120248182d8", + "jsonrpc": "2.0", + "result": { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "1", + "last_block_id": { + "hash": "", + "parts": { + "hash": "", + "total": 0 + } + }, + "last_commit_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:03.391799721Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "", + "parts": { + "hash": "", + "total": 0 + } + }, + "height": "0", + "round": 0, + "signatures": [] + } + }, + "block_id": { + "hash": "D55CD72165688BE21F2DF8C9AE46FA2BCA423223E99FC665DD2E621066F443C5", + "parts": { + "hash": "372520F1B93CD0EC3901006DE2E3CD752C9141628A7B430088DF912171355DDA", + "total": 1 + } + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/block_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_at_height_10.json new file mode 100644 index 000000000..cf482b096 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_at_height_10.json @@ -0,0 +1,65 @@ +{ + "id": "a24afd41-dbab-453d-8734-f599f84eb653", + "jsonrpc": "2.0", + "result": { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "10", + "last_block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D", + "total": 1 + } + }, + "last_commit_hash": "E8DE5F9749FA5785B9B9F106C82233C910C75AE8A0903D1FAB146C1DD4E7A0EC", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:08.140032018Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D", + "total": 1 + } + }, + "height": "9", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "HZvchSiSLgqdRmsZ+KIpkztV7ZbEBhRU5CKHUy0enSHoma8jTk9BC69s4fPvHHLiAtSNausFd83g0KR08bQhCw==", + "timestamp": "2023-02-27T07:13:08.140032018Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "FCF9C2537FC3534CA71001FE1F14C4F769090948C1A521682F612E7CF73AE639", + "parts": { + "hash": "E16EDCB0EC135191F5C017FDF232967F50919E06B0F2F419FA93D006E606CF05", + "total": 1 + } + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/block_by_hash.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_by_hash.json new file mode 100644 index 000000000..5cf5431f5 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_by_hash.json @@ -0,0 +1,65 @@ +{ + "jsonrpc": "2.0", + "id": "56d4851a-1f30-4d73-9f86-c1a084e8aa97", + "result": { + "block_id": { + "hash": "FCF9C2537FC3534CA71001FE1F14C4F769090948C1A521682F612E7CF73AE639", + "parts": { + "total": 1, + "hash": "E16EDCB0EC135191F5C017FDF232967F50919E06B0F2F419FA93D006E606CF05" + } + }, + "block": { + "header": { + "version": { + "block": "11", + "app": "1" + }, + "chain_id": "dockerchain", + "height": "10", + "time": "2023-02-27T07:13:08.140032018Z", + "last_block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "total": 1, + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D" + } + }, + "last_commit_hash": "E8DE5F9749FA5785B9B9F106C82233C910C75AE8A0903D1FAB146C1DD4E7A0EC", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "app_hash": "0000000000000000", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371" + }, + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "last_commit": { + "height": "9", + "round": 0, + "block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "total": 1, + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D" + } + }, + "signatures": [ + { + "block_id_flag": 2, + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371", + "timestamp": "2023-02-27T07:13:08.140032018Z", + "signature": "HZvchSiSLgqdRmsZ+KIpkztV7ZbEBhRU5CKHUy0enSHoma8jTk9BC69s4fPvHHLiAtSNausFd83g0KR08bQhCw==" + } + ] + } + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/block_results_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_results_at_height_10.json new file mode 100644 index 000000000..ee23b39ec --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_results_at_height_10.json @@ -0,0 +1,12 @@ +{ + "id": "77cfdbe4-630e-4b73-b30d-90a1236f96a3", + "jsonrpc": "2.0", + "result": { + "begin_block_events": null, + "consensus_param_updates": null, + "end_block_events": null, + "height": "10", + "txs_results": null, + "validator_updates": null + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/block_search.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_search.json new file mode 100644 index 000000000..69c956186 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/block_search.json @@ -0,0 +1,2758 @@ +{ + "id": "60d0e76b-d645-4b37-adc0-42fc0fa7d394", + "jsonrpc": "2.0", + "result": { + "blocks": [ + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "2", + "last_block_id": { + "hash": "D55CD72165688BE21F2DF8C9AE46FA2BCA423223E99FC665DD2E621066F443C5", + "parts": { + "hash": "372520F1B93CD0EC3901006DE2E3CD752C9141628A7B430088DF912171355DDA", + "total": 1 + } + }, + "last_commit_hash": "48018604B85D54DC6E49DB6E4CF12F67FC56337B84E378AE2357B3E2CE4F1EC9", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:03.991666836Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "D55CD72165688BE21F2DF8C9AE46FA2BCA423223E99FC665DD2E621066F443C5", + "parts": { + "hash": "372520F1B93CD0EC3901006DE2E3CD752C9141628A7B430088DF912171355DDA", + "total": 1 + } + }, + "height": "1", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "cHV87SDszjwySZojpEm59gEXsIn77kchx5HubP1Aw+w9nwAiTiKoVua/rIbSyc6l18Jj3YAtuZ0TiP9bEJv5AQ==", + "timestamp": "2023-02-27T07:13:03.991666836Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "618E263A7265C42E04D4C5DE3370F7B64C0AC8271435D17A20360C09A702E353", + "parts": { + "hash": "23296CEC8762B62711D174F14FFE5807F910AE3360F24BE55B58C1E8911FD01F", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "3", + "last_block_id": { + "hash": "618E263A7265C42E04D4C5DE3370F7B64C0AC8271435D17A20360C09A702E353", + "parts": { + "hash": "23296CEC8762B62711D174F14FFE5807F910AE3360F24BE55B58C1E8911FD01F", + "total": 1 + } + }, + "last_commit_hash": "7183ED105A3A3FF34CBAEB2CDCA13F3C3437EF0A140C40EABA425709AD44C066", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:04.508252675Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "618E263A7265C42E04D4C5DE3370F7B64C0AC8271435D17A20360C09A702E353", + "parts": { + "hash": "23296CEC8762B62711D174F14FFE5807F910AE3360F24BE55B58C1E8911FD01F", + "total": 1 + } + }, + "height": "2", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "KqsqRLvybtHs5pj/G5GH3uVv+9SLWmHxK3eh/omUL026LkpDXiOg70W6ryiurSGVv5CG16q/RI9K4YdFEGNPAQ==", + "timestamp": "2023-02-27T07:13:04.508252675Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "AFEB65E07422484A7295D2ABFEB66621386B98E8FC022B8BD177C14BDB4A3DB2", + "parts": { + "hash": "BC99391E5E093CEEE17A888CE4FA0E13BD06A0BA026336B662D445F5B1455DA9", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "4", + "last_block_id": { + "hash": "AFEB65E07422484A7295D2ABFEB66621386B98E8FC022B8BD177C14BDB4A3DB2", + "parts": { + "hash": "BC99391E5E093CEEE17A888CE4FA0E13BD06A0BA026336B662D445F5B1455DA9", + "total": 1 + } + }, + "last_commit_hash": "97FFFE3763FFAB168334C271B859483B95BF393CF4E61C91590CF3F6F55C4204", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:05.026580561Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "AFEB65E07422484A7295D2ABFEB66621386B98E8FC022B8BD177C14BDB4A3DB2", + "parts": { + "hash": "BC99391E5E093CEEE17A888CE4FA0E13BD06A0BA026336B662D445F5B1455DA9", + "total": 1 + } + }, + "height": "3", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "flGrk8tDwO0+n1QayE7pusw1ZViNwYck7fAHyDkyGCNxqeqttNqchoWSrfHMbBZGjxwqjASPU3HU2GhQ5SDCBA==", + "timestamp": "2023-02-27T07:13:05.026580561Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "7D162051AC61242B7613E085CA4E3488AE6A953E8BE3B72A9E6938E62F5212AF", + "parts": { + "hash": "D9A258567016DE8D364C0E64E3882C7DAD6488B129CE4612B3D67EBFF7CFF288", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "5", + "last_block_id": { + "hash": "7D162051AC61242B7613E085CA4E3488AE6A953E8BE3B72A9E6938E62F5212AF", + "parts": { + "hash": "D9A258567016DE8D364C0E64E3882C7DAD6488B129CE4612B3D67EBFF7CFF288", + "total": 1 + } + }, + "last_commit_hash": "4D95F1B754571826AA7C01E521D1D73A309880714C81DE48255DA2D57D55C756", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:05.545291963Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "7D162051AC61242B7613E085CA4E3488AE6A953E8BE3B72A9E6938E62F5212AF", + "parts": { + "hash": "D9A258567016DE8D364C0E64E3882C7DAD6488B129CE4612B3D67EBFF7CFF288", + "total": 1 + } + }, + "height": "4", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "5P0/jbLaaV9ziN8LYHf9lspfU3VqnWVDo4jDx1gBaC2hvUBG1abRqQufylCzZk1Dq1FOfHOx9snUXULk/Xe0Bw==", + "timestamp": "2023-02-27T07:13:05.545291963Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "38070040A8D1365B66B0344664106193ECF1D18444A769E51D2881B15087DCD7", + "parts": { + "hash": "59876DFD84701B32F2AB5679D498E33A9AC26D11165B142D5E9EF3B2AF021BB9", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "6", + "last_block_id": { + "hash": "38070040A8D1365B66B0344664106193ECF1D18444A769E51D2881B15087DCD7", + "parts": { + "hash": "59876DFD84701B32F2AB5679D498E33A9AC26D11165B142D5E9EF3B2AF021BB9", + "total": 1 + } + }, + "last_commit_hash": "139381A60C8BCAF336ED8E8373FE52F7469DA76C054B9265921322046FD97B93", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:06.065052373Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "38070040A8D1365B66B0344664106193ECF1D18444A769E51D2881B15087DCD7", + "parts": { + "hash": "59876DFD84701B32F2AB5679D498E33A9AC26D11165B142D5E9EF3B2AF021BB9", + "total": 1 + } + }, + "height": "5", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "4unKYY8ShwcpEbS+dqFtHgJSN4Qt0OBKV+DvoWURU+GDFymH4z6yWUNjyVDkazwk0mxOx3NuIYt8oA75taLbDg==", + "timestamp": "2023-02-27T07:13:06.065052373Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "92DF7250265107D9FB3BAC7A97CA25AC2543B86E960632D11DDDE74FB5C2F41F", + "parts": { + "hash": "9F7DCBC5879343913CFAA6365B68E34FEA17CB1E1D1B7044ED72131D1F5DE9F9", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "7", + "last_block_id": { + "hash": "92DF7250265107D9FB3BAC7A97CA25AC2543B86E960632D11DDDE74FB5C2F41F", + "parts": { + "hash": "9F7DCBC5879343913CFAA6365B68E34FEA17CB1E1D1B7044ED72131D1F5DE9F9", + "total": 1 + } + }, + "last_commit_hash": "325A2D023AAA8705C2D9FF1593C8904EF16258825EC8212600BE98C69E20F3D2", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:06.580593612Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "92DF7250265107D9FB3BAC7A97CA25AC2543B86E960632D11DDDE74FB5C2F41F", + "parts": { + "hash": "9F7DCBC5879343913CFAA6365B68E34FEA17CB1E1D1B7044ED72131D1F5DE9F9", + "total": 1 + } + }, + "height": "6", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "4Jr4PkKzZwDIfIs16jJtCfo8Gtce7yOmDwhq6ItoHh6eUkfC9uYVjLAi/GvRqCI7p/T0vGOtxKPt8E5H8N+EAA==", + "timestamp": "2023-02-27T07:13:06.580593612Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "29374DAF235CC5A1751E09A22DD6F200D1EA3BEB473A7820C4CC7F149DB032AB", + "parts": { + "hash": "7AEA98F9C8658AF6B5DE7B41AF0658AACBDC54D882E17BCFB35727B95EAD9E50", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "8", + "last_block_id": { + "hash": "29374DAF235CC5A1751E09A22DD6F200D1EA3BEB473A7820C4CC7F149DB032AB", + "parts": { + "hash": "7AEA98F9C8658AF6B5DE7B41AF0658AACBDC54D882E17BCFB35727B95EAD9E50", + "total": 1 + } + }, + "last_commit_hash": "6B184CC5107EAD2DD682BD3A1A60B568ECB9EE2A75DA34F237E42550B69E3146", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:07.101498447Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "29374DAF235CC5A1751E09A22DD6F200D1EA3BEB473A7820C4CC7F149DB032AB", + "parts": { + "hash": "7AEA98F9C8658AF6B5DE7B41AF0658AACBDC54D882E17BCFB35727B95EAD9E50", + "total": 1 + } + }, + "height": "7", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "feAR9RewFN2wkmn0yfdN0hdwtrvqzF7wqHp/56SO970V4qw7PNP3npTa8lTyuvtWtga2u9ukQCbJuB8IuvP8AQ==", + "timestamp": "2023-02-27T07:13:07.101498447Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "875A50CDD812054D87A7F5CC6A0C7E224C6E2DF2F2A89EA51B9DCEE6136B469E", + "parts": { + "hash": "74F62C8CEF42AF0A685D84C8422751CD2269E16A793FAC95B96A8C42132E8338", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "9", + "last_block_id": { + "hash": "875A50CDD812054D87A7F5CC6A0C7E224C6E2DF2F2A89EA51B9DCEE6136B469E", + "parts": { + "hash": "74F62C8CEF42AF0A685D84C8422751CD2269E16A793FAC95B96A8C42132E8338", + "total": 1 + } + }, + "last_commit_hash": "9EEDE09BD5848E1F97D54D4C2633582D152FEF610869E3D29815B5A2159D8631", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:07.619684947Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "875A50CDD812054D87A7F5CC6A0C7E224C6E2DF2F2A89EA51B9DCEE6136B469E", + "parts": { + "hash": "74F62C8CEF42AF0A685D84C8422751CD2269E16A793FAC95B96A8C42132E8338", + "total": 1 + } + }, + "height": "8", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "wpir5zdPemjY2aY97Xoh9ioNmjc8Kt8eFB3skbYYfiY0AW92FOisfR98reIyoOLRlhnuarSsjZsYIYFn/L8iDw==", + "timestamp": "2023-02-27T07:13:07.619684947Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "10", + "last_block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D", + "total": 1 + } + }, + "last_commit_hash": "E8DE5F9749FA5785B9B9F106C82233C910C75AE8A0903D1FAB146C1DD4E7A0EC", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:08.140032018Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D", + "total": 1 + } + }, + "height": "9", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "HZvchSiSLgqdRmsZ+KIpkztV7ZbEBhRU5CKHUy0enSHoma8jTk9BC69s4fPvHHLiAtSNausFd83g0KR08bQhCw==", + "timestamp": "2023-02-27T07:13:08.140032018Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "FCF9C2537FC3534CA71001FE1F14C4F769090948C1A521682F612E7CF73AE639", + "parts": { + "hash": "E16EDCB0EC135191F5C017FDF232967F50919E06B0F2F419FA93D006E606CF05", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "11", + "last_block_id": { + "hash": "FCF9C2537FC3534CA71001FE1F14C4F769090948C1A521682F612E7CF73AE639", + "parts": { + "hash": "E16EDCB0EC135191F5C017FDF232967F50919E06B0F2F419FA93D006E606CF05", + "total": 1 + } + }, + "last_commit_hash": "62A7ADC65EEFBE1E7146542222F6613C49E037F76E8401AA72C5CD1B879E92EE", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:08.658439642Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "FCF9C2537FC3534CA71001FE1F14C4F769090948C1A521682F612E7CF73AE639", + "parts": { + "hash": "E16EDCB0EC135191F5C017FDF232967F50919E06B0F2F419FA93D006E606CF05", + "total": 1 + } + }, + "height": "10", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "qJblJeAl6OtGRKkOa91+HLzX3ZGl/Nlnl5K9RiT2gRSPgPSjxq+95mSQSJ3b3I38mdZvYLUML6kEGvC/zjlJCQ==", + "timestamp": "2023-02-27T07:13:08.658439642Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "C3BB1826273AC94C4B2C2BCF7B576FA3F081B29D53B61D17A98D354CC37BB35D", + "parts": { + "hash": "79DF166677D4BFF3F062F83B71D2503E75D27D036B9B48A4577F6FA710D959E2", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "12", + "last_block_id": { + "hash": "C3BB1826273AC94C4B2C2BCF7B576FA3F081B29D53B61D17A98D354CC37BB35D", + "parts": { + "hash": "79DF166677D4BFF3F062F83B71D2503E75D27D036B9B48A4577F6FA710D959E2", + "total": 1 + } + }, + "last_commit_hash": "8A9D304F162B3D0DDD5627BE75A1392938798FD058B4A5394559CC980C7C80E8", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:09.177757554Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "C3BB1826273AC94C4B2C2BCF7B576FA3F081B29D53B61D17A98D354CC37BB35D", + "parts": { + "hash": "79DF166677D4BFF3F062F83B71D2503E75D27D036B9B48A4577F6FA710D959E2", + "total": 1 + } + }, + "height": "11", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "AfQHggff6gF+cRzr7r5tAlgWysMoKLM80ukaGroGB8sFcnWqmVRPFYiNxRwRbkzFLKhBNWlajFoDxnESMB8iDg==", + "timestamp": "2023-02-27T07:13:09.177757554Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "A498E33E12FBE7C1F1E9A76CAD1826AC4474A0FD2C402188B93F6674A18D7B08", + "parts": { + "hash": "52619405D70E2FCC699567258AC9C2912F2CCEE4CB5EFC813B0CD2AF4D6B49C0", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "13", + "last_block_id": { + "hash": "A498E33E12FBE7C1F1E9A76CAD1826AC4474A0FD2C402188B93F6674A18D7B08", + "parts": { + "hash": "52619405D70E2FCC699567258AC9C2912F2CCEE4CB5EFC813B0CD2AF4D6B49C0", + "total": 1 + } + }, + "last_commit_hash": "C97CC7FF9E2B8F5627D3955B0CE9E030C848E8D7EBCE50E7A457B57D35A6B75D", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:09.69690345Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "A498E33E12FBE7C1F1E9A76CAD1826AC4474A0FD2C402188B93F6674A18D7B08", + "parts": { + "hash": "52619405D70E2FCC699567258AC9C2912F2CCEE4CB5EFC813B0CD2AF4D6B49C0", + "total": 1 + } + }, + "height": "12", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "HQPxHUxDszRfeefEWSwn5FovRLwaMySeBgyv625gRteCMprVANIKV/GHowhhhvobJSSBkRxC9l6HScWF5PIsBA==", + "timestamp": "2023-02-27T07:13:09.69690345Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "F882C8C72A5E6656C5D53D2C40915588800262669295AEE82D8308CDE968F842", + "parts": { + "hash": "81A9B689C0E49AC0FC938B7F48DE1D8711FEA53B31401656DB499FE5443DCACE", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "14", + "last_block_id": { + "hash": "F882C8C72A5E6656C5D53D2C40915588800262669295AEE82D8308CDE968F842", + "parts": { + "hash": "81A9B689C0E49AC0FC938B7F48DE1D8711FEA53B31401656DB499FE5443DCACE", + "total": 1 + } + }, + "last_commit_hash": "7464603E3DCBC1BE1DD8EFC40B0692C3EBA4F75BB81ABFECDCEC1A21A8186DB3", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:10.216100068Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "F882C8C72A5E6656C5D53D2C40915588800262669295AEE82D8308CDE968F842", + "parts": { + "hash": "81A9B689C0E49AC0FC938B7F48DE1D8711FEA53B31401656DB499FE5443DCACE", + "total": 1 + } + }, + "height": "13", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "xXJpugvhH06QSmLzfRpH1LZjSHdCmc4pKNr9PUEqQ4A7ghioi69bw9GLDahHHmjjK6nS3l5Wir+K04wHxbbwAQ==", + "timestamp": "2023-02-27T07:13:10.216100068Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "0CA458488C5924973E879C0B0133096EC3EC163A402BDA53683119C357EF04FC", + "parts": { + "hash": "08E4B121093A202180C70A3253181FF2C5DE7ABBC14CA06EE900DF6DF591E53A", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "15", + "last_block_id": { + "hash": "0CA458488C5924973E879C0B0133096EC3EC163A402BDA53683119C357EF04FC", + "parts": { + "hash": "08E4B121093A202180C70A3253181FF2C5DE7ABBC14CA06EE900DF6DF591E53A", + "total": 1 + } + }, + "last_commit_hash": "545D3D4B88F316206E79710FF0AB37747A444A783F178FB7ED8502459BC098AC", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:10.733698145Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "0CA458488C5924973E879C0B0133096EC3EC163A402BDA53683119C357EF04FC", + "parts": { + "hash": "08E4B121093A202180C70A3253181FF2C5DE7ABBC14CA06EE900DF6DF591E53A", + "total": 1 + } + }, + "height": "14", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "0gYlNlne7LCIKQ1f955kvioJGvEM7R/SntOLgEIN6F2TvhTp6ye2aNu1ai9hm7kYo7BUM5mdzUf9GMzbmqRqDw==", + "timestamp": "2023-02-27T07:13:10.733698145Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "B1874B46DC158BBE8F036907C4D3C41E6D8F93890B6A17748584EB00004454B9", + "parts": { + "hash": "869D4CEDD32658192B51BD6250AF66F8DCE002463E979F8C4ED1EF1C92FA4715", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "16", + "last_block_id": { + "hash": "B1874B46DC158BBE8F036907C4D3C41E6D8F93890B6A17748584EB00004454B9", + "parts": { + "hash": "869D4CEDD32658192B51BD6250AF66F8DCE002463E979F8C4ED1EF1C92FA4715", + "total": 1 + } + }, + "last_commit_hash": "5FA881010BFCD1A31776F740D4E67E0C13D4D02FCF9ECE328B4CFC6EC527B435", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:11.253510665Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "B1874B46DC158BBE8F036907C4D3C41E6D8F93890B6A17748584EB00004454B9", + "parts": { + "hash": "869D4CEDD32658192B51BD6250AF66F8DCE002463E979F8C4ED1EF1C92FA4715", + "total": 1 + } + }, + "height": "15", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "4MyfaPJqTm/7xWzK9Mw0cSO2S3jqJ9kuWTnjVq9ijLnjEy3p8cWUPBsN5X/Lso0QjluucXgbXVLb2IwU9Lp2Aw==", + "timestamp": "2023-02-27T07:13:11.253510665Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "FA0C794B970417EF8571B92598F985B35ACE451489A1C6723327B38BC4E2ABFA", + "parts": { + "hash": "57EF53E1A703990AE79FAD55D1B40B98FE230BFE247230F2985E7851D99FB86B", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "17", + "last_block_id": { + "hash": "FA0C794B970417EF8571B92598F985B35ACE451489A1C6723327B38BC4E2ABFA", + "parts": { + "hash": "57EF53E1A703990AE79FAD55D1B40B98FE230BFE247230F2985E7851D99FB86B", + "total": 1 + } + }, + "last_commit_hash": "DC79D7766DFC0184E47DBF721FF7D65C3180EF453820E095553E44DB48E8F03E", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:11.772048383Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "FA0C794B970417EF8571B92598F985B35ACE451489A1C6723327B38BC4E2ABFA", + "parts": { + "hash": "57EF53E1A703990AE79FAD55D1B40B98FE230BFE247230F2985E7851D99FB86B", + "total": 1 + } + }, + "height": "16", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "kd81f5ePpxFfoj8dQNmXR4iNfP27LpvUkY84iC9SzoeYfSOLm78PgrCv1KQ87Od2JF3iTKtmqJ1CDu+6PXFyBw==", + "timestamp": "2023-02-27T07:13:11.772048383Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "50BF72F2ABA6F724BCF775B4E4BC2221F0EF5F48678B67324D19A1E5A1C9AB6F", + "parts": { + "hash": "5ACF51411D81C8B286CD61D87F3A42C3BF0DA7DE664683CB058B28B5CA4A188D", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "18", + "last_block_id": { + "hash": "50BF72F2ABA6F724BCF775B4E4BC2221F0EF5F48678B67324D19A1E5A1C9AB6F", + "parts": { + "hash": "5ACF51411D81C8B286CD61D87F3A42C3BF0DA7DE664683CB058B28B5CA4A188D", + "total": 1 + } + }, + "last_commit_hash": "4AC0F9D7369D83FA51520C6A550295F4A5EEA7E5727E8126C9482940C6FE5111", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:12.292293252Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "50BF72F2ABA6F724BCF775B4E4BC2221F0EF5F48678B67324D19A1E5A1C9AB6F", + "parts": { + "hash": "5ACF51411D81C8B286CD61D87F3A42C3BF0DA7DE664683CB058B28B5CA4A188D", + "total": 1 + } + }, + "height": "17", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "u8DKvXrbZGBULm4HOtffluaTwOAiG6/tWmgEoN851xF3mi1+vR9W3noubU80wp9DP55F5DtLKi6vg+6a4KqHAw==", + "timestamp": "2023-02-27T07:13:12.292293252Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "8A00A66D9AC8BE49BCDA0B90587D3347111AF3CD255A5CEEE579B5BA4FCB189A", + "parts": { + "hash": "D5D7DAECB8F5FE498DBB4D4EC492470A0B3044FEA1C5FF3A5A3833F994AB8D37", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "19", + "last_block_id": { + "hash": "8A00A66D9AC8BE49BCDA0B90587D3347111AF3CD255A5CEEE579B5BA4FCB189A", + "parts": { + "hash": "D5D7DAECB8F5FE498DBB4D4EC492470A0B3044FEA1C5FF3A5A3833F994AB8D37", + "total": 1 + } + }, + "last_commit_hash": "0B455D91296AA7790A6BFF5F78D75429483240511B52D97D85C0E2CDF902E505", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:12.811155987Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "8A00A66D9AC8BE49BCDA0B90587D3347111AF3CD255A5CEEE579B5BA4FCB189A", + "parts": { + "hash": "D5D7DAECB8F5FE498DBB4D4EC492470A0B3044FEA1C5FF3A5A3833F994AB8D37", + "total": 1 + } + }, + "height": "18", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "1m1Atw77VtN46HCNtGYbZJ23Kw/NAEQaaW+QEjXoAEtiMK0cOw93nWTFROhSlsqdoB3r0lBf3dSGcFM1byD0CQ==", + "timestamp": "2023-02-27T07:13:12.811155987Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "CEF00B2DEB42D92DDAF40102A661C8FB6AFEF651197083563C1EEDAA4180E3ED", + "parts": { + "hash": "863AD4FF2F1FCC04E8289C5DC8B4B6DA50B097D887E9301FD1937390706A868F", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "20", + "last_block_id": { + "hash": "CEF00B2DEB42D92DDAF40102A661C8FB6AFEF651197083563C1EEDAA4180E3ED", + "parts": { + "hash": "863AD4FF2F1FCC04E8289C5DC8B4B6DA50B097D887E9301FD1937390706A868F", + "total": 1 + } + }, + "last_commit_hash": "C6687D1B3AB5DF780BF7DC42F0248D06CFD116DA97F1D21C10FE112334DC6377", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:13.330709592Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "CEF00B2DEB42D92DDAF40102A661C8FB6AFEF651197083563C1EEDAA4180E3ED", + "parts": { + "hash": "863AD4FF2F1FCC04E8289C5DC8B4B6DA50B097D887E9301FD1937390706A868F", + "total": 1 + } + }, + "height": "19", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "bnH5D+wDGZJkYDgil9MI0sgf5An2LgP7oK12Xqx530bPG1YHKnS4FTG9ZHX7TBult2zjixDvjjSTLmAcIvpWDA==", + "timestamp": "2023-02-27T07:13:13.330709592Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "2634DD91BA534C06FC1D2F7C8A28D47D23809A8AC8FBEC36BB97F9C25ED0B84E", + "parts": { + "hash": "2EE8FC2C3697C270058987C042E541B4FADCF2814D1613D5AF5A12F5D9F4CF57", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "21", + "last_block_id": { + "hash": "2634DD91BA534C06FC1D2F7C8A28D47D23809A8AC8FBEC36BB97F9C25ED0B84E", + "parts": { + "hash": "2EE8FC2C3697C270058987C042E541B4FADCF2814D1613D5AF5A12F5D9F4CF57", + "total": 1 + } + }, + "last_commit_hash": "0E4FB3AB7E747FAB94B8A8CF48AEBE8A595792275F1078C3C9151660DE58F184", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:13.84781205Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "2634DD91BA534C06FC1D2F7C8A28D47D23809A8AC8FBEC36BB97F9C25ED0B84E", + "parts": { + "hash": "2EE8FC2C3697C270058987C042E541B4FADCF2814D1613D5AF5A12F5D9F4CF57", + "total": 1 + } + }, + "height": "20", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "TvQbxCI6cQUgj3PCayXyjQBxNn2En8l28tpbvbTGRQ5CcTkzJou4Z8gfvjGRV+VTfLfm8To+jv0cLP7d4VCwBQ==", + "timestamp": "2023-02-27T07:13:13.84781205Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "EC16F423E1BDCAF735D57DF3228AFC4C4809EABB0DDCC5C5A5620F92E10C875B", + "parts": { + "hash": "A2BA8E783EE4BC0CC7A6A0B26136EFA055ECA37C6FB3B2BB582169B7BB9EC842", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "22", + "last_block_id": { + "hash": "EC16F423E1BDCAF735D57DF3228AFC4C4809EABB0DDCC5C5A5620F92E10C875B", + "parts": { + "hash": "A2BA8E783EE4BC0CC7A6A0B26136EFA055ECA37C6FB3B2BB582169B7BB9EC842", + "total": 1 + } + }, + "last_commit_hash": "77B2354E5AEC2D118E522FB017C7827D7A52AA6F8B32AE0A46CA389F1B90380A", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:14.367045487Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "EC16F423E1BDCAF735D57DF3228AFC4C4809EABB0DDCC5C5A5620F92E10C875B", + "parts": { + "hash": "A2BA8E783EE4BC0CC7A6A0B26136EFA055ECA37C6FB3B2BB582169B7BB9EC842", + "total": 1 + } + }, + "height": "21", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "XTAJHuY8fqbTnJD0/QwR8E6528bQrY8NuZIJWMlagfOLX5ia/sdyhQMG+oXrpNFSJRREK44SkoViBA910gG/Dg==", + "timestamp": "2023-02-27T07:13:14.367045487Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "AA1C5F527207807EB5709FAB6BD2FF8FF34B81B4BB763F7C2720F349E5DA3A6F", + "parts": { + "hash": "71E731D91E384197F4744B7EE142DFD57820934EED592E4232A7C4482F00C1E9", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "23", + "last_block_id": { + "hash": "AA1C5F527207807EB5709FAB6BD2FF8FF34B81B4BB763F7C2720F349E5DA3A6F", + "parts": { + "hash": "71E731D91E384197F4744B7EE142DFD57820934EED592E4232A7C4482F00C1E9", + "total": 1 + } + }, + "last_commit_hash": "7641A010A1A7AF124EE75C362487648AF979F7B0F79443C38348A3F1FB6903CA", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:14.883931989Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "AA1C5F527207807EB5709FAB6BD2FF8FF34B81B4BB763F7C2720F349E5DA3A6F", + "parts": { + "hash": "71E731D91E384197F4744B7EE142DFD57820934EED592E4232A7C4482F00C1E9", + "total": 1 + } + }, + "height": "22", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "j8+WpHt31HBcLW7eTvC7Utbsym5Rw0IIE7kqpEO4kPrpbLf76Gpa//IqrYU6Lli2S7YZYQUM96xu3Y5OCXWGAg==", + "timestamp": "2023-02-27T07:13:14.883931989Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "221E1A298F3673BBACF9C253D3D86458FFF33C2C04EF054DA6BEAD66A7F1F507", + "parts": { + "hash": "45C107FA7763BF3E639E5281C0313D0AB96E17C57F538439775FBF2AA4DB4C97", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "24", + "last_block_id": { + "hash": "221E1A298F3673BBACF9C253D3D86458FFF33C2C04EF054DA6BEAD66A7F1F507", + "parts": { + "hash": "45C107FA7763BF3E639E5281C0313D0AB96E17C57F538439775FBF2AA4DB4C97", + "total": 1 + } + }, + "last_commit_hash": "E5E10E13CECB5BFDA5E8EE9DC216742D01225296FD26BCD730BCD9604248B537", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:15.400851421Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "221E1A298F3673BBACF9C253D3D86458FFF33C2C04EF054DA6BEAD66A7F1F507", + "parts": { + "hash": "45C107FA7763BF3E639E5281C0313D0AB96E17C57F538439775FBF2AA4DB4C97", + "total": 1 + } + }, + "height": "23", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "VGTRKh5UWC6ZFwCIB9mQU+Jr13cuCWi98C2aqvfMmOZe7EsxAQO1gkOPBa5pDaPTi/QE4F4fhQbDnxVCecNKAg==", + "timestamp": "2023-02-27T07:13:15.400851421Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "5375D153345342F2C89C28956D49552DAC8383E431E43D1ABDBA851C823C3FFF", + "parts": { + "hash": "4082B761350D2AEB86C4060E25C43202586C0134C74A70AB386A70A3E31264EF", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "25", + "last_block_id": { + "hash": "5375D153345342F2C89C28956D49552DAC8383E431E43D1ABDBA851C823C3FFF", + "parts": { + "hash": "4082B761350D2AEB86C4060E25C43202586C0134C74A70AB386A70A3E31264EF", + "total": 1 + } + }, + "last_commit_hash": "724CD0C3D5132EF8DD2FA841F802544D4360378345976AB7EB5131821ED8FD0B", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:15.91961831Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "5375D153345342F2C89C28956D49552DAC8383E431E43D1ABDBA851C823C3FFF", + "parts": { + "hash": "4082B761350D2AEB86C4060E25C43202586C0134C74A70AB386A70A3E31264EF", + "total": 1 + } + }, + "height": "24", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "bntLcLPd35sdA/Pw7mAOrm3yh55Sfb5D1VV/CljoVF/qKmJ6pdLduE1ola6yuWThd1Q9qq/QDikj5Ytjt15fAQ==", + "timestamp": "2023-02-27T07:13:15.91961831Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "21AD6D7033246D7B6CFA05FFDE19D4DF6A1C9FB9E090697B2993E4D59509EA46", + "parts": { + "hash": "0E1EDD0BC691BAA08751E4BEC83498724FDFB43E756FCB2D29139095C6B94D34", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "26", + "last_block_id": { + "hash": "21AD6D7033246D7B6CFA05FFDE19D4DF6A1C9FB9E090697B2993E4D59509EA46", + "parts": { + "hash": "0E1EDD0BC691BAA08751E4BEC83498724FDFB43E756FCB2D29139095C6B94D34", + "total": 1 + } + }, + "last_commit_hash": "C47978AE0D65FD44E94D09883E1C05138AC1BA66340F693FC29F74F8C105BFE8", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:16.438813001Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "21AD6D7033246D7B6CFA05FFDE19D4DF6A1C9FB9E090697B2993E4D59509EA46", + "parts": { + "hash": "0E1EDD0BC691BAA08751E4BEC83498724FDFB43E756FCB2D29139095C6B94D34", + "total": 1 + } + }, + "height": "25", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "pxB5d8q+mDQF+AhHY4q6RwGUNsCZCkm6FWmCkLXfNQkd6MjnXTSBVdW8LTUGI0DXJzur7rtJ7+Ot5BeM4oemCw==", + "timestamp": "2023-02-27T07:13:16.438813001Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "C397C5FCB0D02489BF9CF73CA2CB70F5B86D3EC6EF492D5D51765243FE41DEDC", + "parts": { + "hash": "36196006C0636E4B205A5BDFDF5C1FA67A7E4B36FE278C3A73D3ED0314CB6673", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "27", + "last_block_id": { + "hash": "C397C5FCB0D02489BF9CF73CA2CB70F5B86D3EC6EF492D5D51765243FE41DEDC", + "parts": { + "hash": "36196006C0636E4B205A5BDFDF5C1FA67A7E4B36FE278C3A73D3ED0314CB6673", + "total": 1 + } + }, + "last_commit_hash": "74315BD12E76A7790F3CEFCF3F7CFC0E4CE67C59F1BFAFFED428E56AA08CEE35", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:16.955412315Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "C397C5FCB0D02489BF9CF73CA2CB70F5B86D3EC6EF492D5D51765243FE41DEDC", + "parts": { + "hash": "36196006C0636E4B205A5BDFDF5C1FA67A7E4B36FE278C3A73D3ED0314CB6673", + "total": 1 + } + }, + "height": "26", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "P4wVGRmrhGWxxNNXtIa/L+jYSkwlu4biRLSR8v3m+se+PP1J7NE1JfVV0E85SsWTkPO6MJi1GQKF0RNrPqUBBQ==", + "timestamp": "2023-02-27T07:13:16.955412315Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "A997EB5E71BA3605FFB2916D4025095F67E84064BC81FADD6EA818889DDC4C8B", + "parts": { + "hash": "62D6554CEFF8B6ECCA27022E7450768BFCB39CDADE3FB56C20334BFFE0E614A5", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "28", + "last_block_id": { + "hash": "A997EB5E71BA3605FFB2916D4025095F67E84064BC81FADD6EA818889DDC4C8B", + "parts": { + "hash": "62D6554CEFF8B6ECCA27022E7450768BFCB39CDADE3FB56C20334BFFE0E614A5", + "total": 1 + } + }, + "last_commit_hash": "622D840007961BD6135BA325A99B52C19108394AFE693E9F6DC3E64B7847DA37", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:17.473702171Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "A997EB5E71BA3605FFB2916D4025095F67E84064BC81FADD6EA818889DDC4C8B", + "parts": { + "hash": "62D6554CEFF8B6ECCA27022E7450768BFCB39CDADE3FB56C20334BFFE0E614A5", + "total": 1 + } + }, + "height": "27", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "NE0Ps+1vBgXAWiOx2EVDIOoLhcx2pfpmUEEQ4h5XlLd+7cgvqtCF1ipCF7uEj/iWusMUaP2TU7IEUlXKxVEBBA==", + "timestamp": "2023-02-27T07:13:17.473702171Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "332ADA488F8802C730A28D7E69FA88A8E20FD11F76C113A54C7834E4B1772F0E", + "parts": { + "hash": "D61089F0DD5EEFFB84AC4FBEB2E61118754171B45D9DADF425A0BC94704531EE", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "29", + "last_block_id": { + "hash": "332ADA488F8802C730A28D7E69FA88A8E20FD11F76C113A54C7834E4B1772F0E", + "parts": { + "hash": "D61089F0DD5EEFFB84AC4FBEB2E61118754171B45D9DADF425A0BC94704531EE", + "total": 1 + } + }, + "last_commit_hash": "C8BA6653CADB5C952818F5C5ED14ABD0AF7BEE8114D30870CFC05BBAADE668B8", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:17.99240594Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "332ADA488F8802C730A28D7E69FA88A8E20FD11F76C113A54C7834E4B1772F0E", + "parts": { + "hash": "D61089F0DD5EEFFB84AC4FBEB2E61118754171B45D9DADF425A0BC94704531EE", + "total": 1 + } + }, + "height": "28", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "RETPQXHWK4g8F9CjcZnz6uvvj41fkC8rCa4VZJbnF5PK2IAl/ZfhfG3XgrxM7/JqUJlXpavDcb3DrIV4KXz6Dw==", + "timestamp": "2023-02-27T07:13:17.99240594Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "4D02C7180E617EFD1A3B266ED68A6E97A9B79BAD86118D40A0701398759F3B2F", + "parts": { + "hash": "2654E6F0B0B7C8F067042A19C5EA85EBC2EC5BBBB1DE0137B78EAF6AC8B86A80", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "30", + "last_block_id": { + "hash": "4D02C7180E617EFD1A3B266ED68A6E97A9B79BAD86118D40A0701398759F3B2F", + "parts": { + "hash": "2654E6F0B0B7C8F067042A19C5EA85EBC2EC5BBBB1DE0137B78EAF6AC8B86A80", + "total": 1 + } + }, + "last_commit_hash": "8CE039485C6EBC7D0E35B42960EC9713768A87ADDD923849CD24C7CD358BA2C8", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:18.508531314Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "4D02C7180E617EFD1A3B266ED68A6E97A9B79BAD86118D40A0701398759F3B2F", + "parts": { + "hash": "2654E6F0B0B7C8F067042A19C5EA85EBC2EC5BBBB1DE0137B78EAF6AC8B86A80", + "total": 1 + } + }, + "height": "29", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "5L5B8U8HPUWInJTd2meNt8Y6HjPdai8d0WuSQF17UpGhNI+T9NmZWGmmpIYR6DgMxBor5p3friMhU41stRisAw==", + "timestamp": "2023-02-27T07:13:18.508531314Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "0BBED93EC119E0614BD942A2CF97054EAEB8F35B9F40E61E2BDDB618735E694D", + "parts": { + "hash": "78B4E28177F5C19B34979E1F836419B16FDE82944FB9865B1A4A2BC4093DE51F", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "31", + "last_block_id": { + "hash": "0BBED93EC119E0614BD942A2CF97054EAEB8F35B9F40E61E2BDDB618735E694D", + "parts": { + "hash": "78B4E28177F5C19B34979E1F836419B16FDE82944FB9865B1A4A2BC4093DE51F", + "total": 1 + } + }, + "last_commit_hash": "299DC98899FDC5AF9E41F25749BCD0F3A2AEA4640A6EF98861DD0D7CA4771C51", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:19.026486127Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "0BBED93EC119E0614BD942A2CF97054EAEB8F35B9F40E61E2BDDB618735E694D", + "parts": { + "hash": "78B4E28177F5C19B34979E1F836419B16FDE82944FB9865B1A4A2BC4093DE51F", + "total": 1 + } + }, + "height": "30", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "5TggCukcXyElGgBR216H2lY9p/yOKTzed36fmWlqlEQTbQgpbvE8v267TNteJ82gQN9BGv2XpeTbxqHRNLjKBw==", + "timestamp": "2023-02-27T07:13:19.026486127Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "1586A4047F502F960CB77D0EA045AFA374380E6A63690D5E4182223DC5741919", + "parts": { + "hash": "3F9ACB43E54AAE66CC20B5187CFAD0E3F0844F7F52E6B578C283B16CED63E7A9", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "32", + "last_block_id": { + "hash": "1586A4047F502F960CB77D0EA045AFA374380E6A63690D5E4182223DC5741919", + "parts": { + "hash": "3F9ACB43E54AAE66CC20B5187CFAD0E3F0844F7F52E6B578C283B16CED63E7A9", + "total": 1 + } + }, + "last_commit_hash": "F84E5533989FE76D88BB66DDFA8DAB11142D99887EF89D78D45B73B9C2FE9AFC", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:19.546024738Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "1586A4047F502F960CB77D0EA045AFA374380E6A63690D5E4182223DC5741919", + "parts": { + "hash": "3F9ACB43E54AAE66CC20B5187CFAD0E3F0844F7F52E6B578C283B16CED63E7A9", + "total": 1 + } + }, + "height": "31", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "d2BJXBNmf2kIvk5gXvUQ364BDUVcAbn5s9Rj21cE4alscThTddrpLmi4W2zEeT+kvVUArzxyfSSnoNpMy3eBCw==", + "timestamp": "2023-02-27T07:13:19.546024738Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "E4579B240F3768A0FE31685FC19856948E4822C6E8B2ACBC01ACC5E98AB182AA", + "parts": { + "hash": "E0FCFF10A52FB934412299A3715031FAE56DDB8007D6E60E11F839B26DDC256D", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "33", + "last_block_id": { + "hash": "E4579B240F3768A0FE31685FC19856948E4822C6E8B2ACBC01ACC5E98AB182AA", + "parts": { + "hash": "E0FCFF10A52FB934412299A3715031FAE56DDB8007D6E60E11F839B26DDC256D", + "total": 1 + } + }, + "last_commit_hash": "88A6D85E49707A9097E9CEC884FDD02567774C4882AB78DFEDE008479A9E42C0", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:20.062271708Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "E4579B240F3768A0FE31685FC19856948E4822C6E8B2ACBC01ACC5E98AB182AA", + "parts": { + "hash": "E0FCFF10A52FB934412299A3715031FAE56DDB8007D6E60E11F839B26DDC256D", + "total": 1 + } + }, + "height": "32", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "LRUxW7Z2Y0WiZz7htYlLE6Q2YuqvysXglHOqp2kd7AQLEqZO3EO5bkDq14EfwlhF25VHu6N1x7FC+tXxLQMzDg==", + "timestamp": "2023-02-27T07:13:20.062271708Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "280529F1C02C8C5AD9CD7A2219ABE33075861A1340816CCDB66AF2AFF5417DF6", + "parts": { + "hash": "5C551163ECAE74A6AF25B7A66C3511D819BA7201417534FE1D46FE1F93A618E6", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "34", + "last_block_id": { + "hash": "280529F1C02C8C5AD9CD7A2219ABE33075861A1340816CCDB66AF2AFF5417DF6", + "parts": { + "hash": "5C551163ECAE74A6AF25B7A66C3511D819BA7201417534FE1D46FE1F93A618E6", + "total": 1 + } + }, + "last_commit_hash": "957AC5C102E4EBD57165C8E318C1FB22843BF295AEBF47A3C31EFF5F9BA0003C", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:20.579531491Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "280529F1C02C8C5AD9CD7A2219ABE33075861A1340816CCDB66AF2AFF5417DF6", + "parts": { + "hash": "5C551163ECAE74A6AF25B7A66C3511D819BA7201417534FE1D46FE1F93A618E6", + "total": 1 + } + }, + "height": "33", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "86HJERRnCVo7BT1VPN94JVvgqWZjB+qkf2aNCs9QItvJpjHyVbxXoIKVqK7dXXd9CJRn8EweOrESDuZa1EJTCA==", + "timestamp": "2023-02-27T07:13:20.579531491Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "0C292C18A10768F9BBE99FF584CBB748133D6B3B89CC09560A1765E82067B231", + "parts": { + "hash": "51076F051D5B73B5B5FAEEB09DF9DC047D30028A4E6AB2E39E55C9C4C92BBF1E", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "35", + "last_block_id": { + "hash": "0C292C18A10768F9BBE99FF584CBB748133D6B3B89CC09560A1765E82067B231", + "parts": { + "hash": "51076F051D5B73B5B5FAEEB09DF9DC047D30028A4E6AB2E39E55C9C4C92BBF1E", + "total": 1 + } + }, + "last_commit_hash": "C256C5585769FE104B36F2381B3C9F769CFCA690B994457EFA837FD56A7D565E", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:21.097684701Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "0C292C18A10768F9BBE99FF584CBB748133D6B3B89CC09560A1765E82067B231", + "parts": { + "hash": "51076F051D5B73B5B5FAEEB09DF9DC047D30028A4E6AB2E39E55C9C4C92BBF1E", + "total": 1 + } + }, + "height": "34", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "8ER+3S/UWdC54DyWTlvOkUmEtXumrFI9wZ4d/Zw4dh/G1O+oWH3L+GFxLhH1NZxavzq5ZmG47PpILO9S09CfAA==", + "timestamp": "2023-02-27T07:13:21.097684701Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "C27CC8C16C955A10E9186D11DDCA8F22FCFE80772896D361A27A268813B3EE33", + "parts": { + "hash": "39FA6D103A177D71DA297AEAC225D9FBDD31F3226D2BC015EDBBEC19DB0D9688", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "36", + "last_block_id": { + "hash": "C27CC8C16C955A10E9186D11DDCA8F22FCFE80772896D361A27A268813B3EE33", + "parts": { + "hash": "39FA6D103A177D71DA297AEAC225D9FBDD31F3226D2BC015EDBBEC19DB0D9688", + "total": 1 + } + }, + "last_commit_hash": "E1F345D8382871FA8CE2895D62948569A5F686BABB1C83450FD01AB8481A6F1E", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:21.613643515Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "C27CC8C16C955A10E9186D11DDCA8F22FCFE80772896D361A27A268813B3EE33", + "parts": { + "hash": "39FA6D103A177D71DA297AEAC225D9FBDD31F3226D2BC015EDBBEC19DB0D9688", + "total": 1 + } + }, + "height": "35", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "2a+7yo2Zq7zJ1R/m4q4dA3CaebeuErlKuyKq4IgUNKLQFWYfAaEl12gAoSVGXyMHuAX6tdgTty7JvabZXAT9AQ==", + "timestamp": "2023-02-27T07:13:21.613643515Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "D7C392D575FFFF42527F2D8B8BC344DBF1973946CB093FCE67C754E0879D9F5D", + "parts": { + "hash": "3E9868A5FE6A64001E2F353EF163D4D652014FF173F6842FEDE5ABA208967786", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "37", + "last_block_id": { + "hash": "D7C392D575FFFF42527F2D8B8BC344DBF1973946CB093FCE67C754E0879D9F5D", + "parts": { + "hash": "3E9868A5FE6A64001E2F353EF163D4D652014FF173F6842FEDE5ABA208967786", + "total": 1 + } + }, + "last_commit_hash": "9E577767C3956B8E35289B1AE84923B92ABD6AAEAE7169CFAB0FCA7E5E881E68", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:22.128368816Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "D7C392D575FFFF42527F2D8B8BC344DBF1973946CB093FCE67C754E0879D9F5D", + "parts": { + "hash": "3E9868A5FE6A64001E2F353EF163D4D652014FF173F6842FEDE5ABA208967786", + "total": 1 + } + }, + "height": "36", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "FrWFxxpFxQjoTluJwBR/9EwKMMv1rf4SP1lgQHJbIiH1wq8gzcotmGJtrhMk0ctmFpLr+f57t5UXlnFrDB6aAg==", + "timestamp": "2023-02-27T07:13:22.128368816Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "CC863DFF7148A845E97269742D31FAC667301EBAB3BF842100C7E1C304BB1569", + "parts": { + "hash": "EE3D68BD7F4863AF4083007C0E6FFD6F09ABA63CD410256003F42BC0889A9E04", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "38", + "last_block_id": { + "hash": "CC863DFF7148A845E97269742D31FAC667301EBAB3BF842100C7E1C304BB1569", + "parts": { + "hash": "EE3D68BD7F4863AF4083007C0E6FFD6F09ABA63CD410256003F42BC0889A9E04", + "total": 1 + } + }, + "last_commit_hash": "C6A23E6D8D90F72EE07538E667B39ED046EF1E8F669A3AF08F440C425099F18F", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:22.647325562Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "CC863DFF7148A845E97269742D31FAC667301EBAB3BF842100C7E1C304BB1569", + "parts": { + "hash": "EE3D68BD7F4863AF4083007C0E6FFD6F09ABA63CD410256003F42BC0889A9E04", + "total": 1 + } + }, + "height": "37", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "tXpMkMZPnUTeChxQJwufS34T7k2qdTT/n88WZJ+GiQfXe3UxVWsuxdc0v8j+GJ29SGncKNtyM8RV5mHr3uZnCA==", + "timestamp": "2023-02-27T07:13:22.647325562Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "ADA6DCD31CBD4273F85E25DA046E90D12223A2916A2613E5A32B54A0FBEECDAC", + "parts": { + "hash": "AC4DF8CA17F14EE067830EDFFEEF59827AB4F83EDF1777937CA6578CF19534A8", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "39", + "last_block_id": { + "hash": "ADA6DCD31CBD4273F85E25DA046E90D12223A2916A2613E5A32B54A0FBEECDAC", + "parts": { + "hash": "AC4DF8CA17F14EE067830EDFFEEF59827AB4F83EDF1777937CA6578CF19534A8", + "total": 1 + } + }, + "last_commit_hash": "2304ECDACC010368C6302ADE0989592BEC84A40DC099DD23A6DD9493DBA1B35D", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:23.163704537Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "ADA6DCD31CBD4273F85E25DA046E90D12223A2916A2613E5A32B54A0FBEECDAC", + "parts": { + "hash": "AC4DF8CA17F14EE067830EDFFEEF59827AB4F83EDF1777937CA6578CF19534A8", + "total": 1 + } + }, + "height": "38", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "oryTv+Nza/Qb3ybWIjYunkLaGAx4QqfiKBSFda1VTsWRchgP/EH7StA1e2DrM4e+Uhzyzr5zBLxi5PmDwQRSAg==", + "timestamp": "2023-02-27T07:13:23.163704537Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "ABCB2A724CAD1809B335D5FF41EE17A62D4A8ECB335F982BA0B319FD46B0D35C", + "parts": { + "hash": "6E236B0A21E1E4DDCCCE5B9B0B783D1919FFF07EDCDECC113DF8D1C5949DA6DE", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "40", + "last_block_id": { + "hash": "ABCB2A724CAD1809B335D5FF41EE17A62D4A8ECB335F982BA0B319FD46B0D35C", + "parts": { + "hash": "6E236B0A21E1E4DDCCCE5B9B0B783D1919FFF07EDCDECC113DF8D1C5949DA6DE", + "total": 1 + } + }, + "last_commit_hash": "605159EE9CCB5F8E320604E4D910258FBE5E56933F023336EC5165D3F6058AC4", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:23.681914368Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "ABCB2A724CAD1809B335D5FF41EE17A62D4A8ECB335F982BA0B319FD46B0D35C", + "parts": { + "hash": "6E236B0A21E1E4DDCCCE5B9B0B783D1919FFF07EDCDECC113DF8D1C5949DA6DE", + "total": 1 + } + }, + "height": "39", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "MtwMuC0q/Cj6ThSTpT2OI6prgfedVNUTGxKyIbVsZ0gM3p4KMJuzkVqsIUhoV26TYVFt8WW9xV0dx8n1eMU3Dg==", + "timestamp": "2023-02-27T07:13:23.681914368Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "EF683A46688EA9936423FA44AFBCFDFE5834D33F41FA39C4BC431FE4A40E5743", + "parts": { + "hash": "663206DE5298F15EF96D5AC077B4A45D93EDFEACB2342871478A92ECB511632B", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "41", + "last_block_id": { + "hash": "EF683A46688EA9936423FA44AFBCFDFE5834D33F41FA39C4BC431FE4A40E5743", + "parts": { + "hash": "663206DE5298F15EF96D5AC077B4A45D93EDFEACB2342871478A92ECB511632B", + "total": 1 + } + }, + "last_commit_hash": "02434C21AA2B70E377C4C8E70CAE91BD2B4006E8EADAC6BD5A3D1C8539042A3C", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:24.200368546Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "EF683A46688EA9936423FA44AFBCFDFE5834D33F41FA39C4BC431FE4A40E5743", + "parts": { + "hash": "663206DE5298F15EF96D5AC077B4A45D93EDFEACB2342871478A92ECB511632B", + "total": 1 + } + }, + "height": "40", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "CM8N52IHprk8ULK8lYxPBpvcVdPjlfrt3TUAR8Y1ebn0mnPuPn83wZHkS+3lHyQoAkjqR6U16t4CYEMAkVOFAw==", + "timestamp": "2023-02-27T07:13:24.200368546Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "CC7D4CB73447307A95ECBF1D0B837320DBC22D874834D14CAED655329A73C642", + "parts": { + "hash": "D06054879F621E56B2192BA6E7304C3C46C127BDB6606EBAF56D0BEAD6DEA82C", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "42", + "last_block_id": { + "hash": "CC7D4CB73447307A95ECBF1D0B837320DBC22D874834D14CAED655329A73C642", + "parts": { + "hash": "D06054879F621E56B2192BA6E7304C3C46C127BDB6606EBAF56D0BEAD6DEA82C", + "total": 1 + } + }, + "last_commit_hash": "7E3CDB1B0034B92CA1902F3DF7329731931F276A9CD4D34FAB6A1AF7648EB28A", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:24.718329395Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "CC7D4CB73447307A95ECBF1D0B837320DBC22D874834D14CAED655329A73C642", + "parts": { + "hash": "D06054879F621E56B2192BA6E7304C3C46C127BDB6606EBAF56D0BEAD6DEA82C", + "total": 1 + } + }, + "height": "41", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "BCnSE2GonfwP3HA3TLmj4WvGPB1evjb4v81a1GYq0iL2TUGfEj9T1TNJ1rxiNj9DU6zyVKswuMfu4XWnXm8xDQ==", + "timestamp": "2023-02-27T07:13:24.718329395Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "D950D40AAAE1F6259FF935BEB3187FDEE0655929CD79FEC2F10191EA179A60CF", + "parts": { + "hash": "7BB111FBD4AC0988D5844EAC762A8AAC0F669499EAE193F2FB3172F60E892B4E", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "43", + "last_block_id": { + "hash": "D950D40AAAE1F6259FF935BEB3187FDEE0655929CD79FEC2F10191EA179A60CF", + "parts": { + "hash": "7BB111FBD4AC0988D5844EAC762A8AAC0F669499EAE193F2FB3172F60E892B4E", + "total": 1 + } + }, + "last_commit_hash": "F863A4B7E2B7CA476D2D6DA428A44F14CD0259A2348951F568AAA1058EC4E0F1", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:25.234615677Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "D950D40AAAE1F6259FF935BEB3187FDEE0655929CD79FEC2F10191EA179A60CF", + "parts": { + "hash": "7BB111FBD4AC0988D5844EAC762A8AAC0F669499EAE193F2FB3172F60E892B4E", + "total": 1 + } + }, + "height": "42", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "meGomIHoovUqNP6s8mjG7Is1tq5keX/0v8sHt9PL9JmZzLs0lcJdAJUudV2dPJ6npdbf4plFKh2YorXJA/BkDg==", + "timestamp": "2023-02-27T07:13:25.234615677Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "1E09DE09FB873F2666804C0A205C485B8D6468D5D99C912E4ACC91581F5CD0C1", + "parts": { + "hash": "20233DC994CDC8A68372D9667E8FE6C2C901D66B91D61F4A8DF9EED73FEBC3DF", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [ + "YXN5bmMta2V5PXZhbHVl" + ] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "3081F9915040D138B3AD7F895732D2767C29E85BA5D84388D04E17A5D8262B7A", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "44", + "last_block_id": { + "hash": "1E09DE09FB873F2666804C0A205C485B8D6468D5D99C912E4ACC91581F5CD0C1", + "parts": { + "hash": "20233DC994CDC8A68372D9667E8FE6C2C901D66B91D61F4A8DF9EED73FEBC3DF", + "total": 1 + } + }, + "last_commit_hash": "0AC8B58D0377A745D0BF94E6DD9541566FE11352560FF198F51460C4D798EC98", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:25.753992404Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "1E09DE09FB873F2666804C0A205C485B8D6468D5D99C912E4ACC91581F5CD0C1", + "parts": { + "hash": "20233DC994CDC8A68372D9667E8FE6C2C901D66B91D61F4A8DF9EED73FEBC3DF", + "total": 1 + } + }, + "height": "43", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "ouOHiTQh6PPLBnNbglHLD4OvBdk5DVsl7HKxgF5xVa7GsVbcvvNGubBhQhjH5TEkFwKofBFPmpjg2S9DIFXGDg==", + "timestamp": "2023-02-27T07:13:25.753992404Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "471637D10971D4D4BC56465EEA4BA02789A99B12A54EDDEF422EC3E78F8A8692", + "parts": { + "hash": "006E91F757AB76E6DE64ED6E837FA1225801687EB77B1CB882393784C388E067", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0200000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "45", + "last_block_id": { + "hash": "471637D10971D4D4BC56465EEA4BA02789A99B12A54EDDEF422EC3E78F8A8692", + "parts": { + "hash": "006E91F757AB76E6DE64ED6E837FA1225801687EB77B1CB882393784C388E067", + "total": 1 + } + }, + "last_commit_hash": "F0B4C270907079C04524BC33EDC008E9AD2EC973051011D3800C474D46712CFD", + "last_results_hash": "6E340B9CFFB37A989CA544E6BB780A2C78901D3FB33738768511A30617AFA01D", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:26.270685966Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "471637D10971D4D4BC56465EEA4BA02789A99B12A54EDDEF422EC3E78F8A8692", + "parts": { + "hash": "006E91F757AB76E6DE64ED6E837FA1225801687EB77B1CB882393784C388E067", + "total": 1 + } + }, + "height": "44", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "DI4FTJW7WPIZ/Jdm7c8jWoQzHKLPzq0gWoXme3YduptR+i8VBh08p6AkaeIqCQAJV1ZqsSDyenP2Spm0JCGJCQ==", + "timestamp": "2023-02-27T07:13:26.270685966Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "A85E6D6F23F865376ADB1509AFC2D13B58508D0E1F41DD20E81BAFA28AF79686", + "parts": { + "hash": "83E8A7B94EC525DCFA31176D75F77A8F427AAAC716AB3C576B092D64AC934726", + "total": 1 + } + } + }, + { + "block": { + "data": { + "txs": [ + "c3luYy1rZXk9dmFsdWU=" + ] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0200000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "A0BF8E611A3A2ED0FE94AA345B903691C3E56EDE0E7F773F54DE7B020E788849", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "46", + "last_block_id": { + "hash": "A85E6D6F23F865376ADB1509AFC2D13B58508D0E1F41DD20E81BAFA28AF79686", + "parts": { + "hash": "83E8A7B94EC525DCFA31176D75F77A8F427AAAC716AB3C576B092D64AC934726", + "total": 1 + } + }, + "last_commit_hash": "AFB39E43529CAA46B433C3AEEEF06AB1BB95E68E90F7037C0F477F16E420AE17", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:26.790394939Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "A85E6D6F23F865376ADB1509AFC2D13B58508D0E1F41DD20E81BAFA28AF79686", + "parts": { + "hash": "83E8A7B94EC525DCFA31176D75F77A8F427AAAC716AB3C576B092D64AC934726", + "total": 1 + } + }, + "height": "45", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "CL378kU/Vcq9YBymUUopYln16O9e14w044GPz2R9rp+mLr/wz+HO4ZRPDEGJh3+y84+dfmO1xJk8VAZxUBBlBw==", + "timestamp": "2023-02-27T07:13:26.790394939Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "block_id": { + "hash": "2490417BFCE699B5C64AF27F28839C7F4D401C8C4C8095308E9247991BABE21C", + "parts": { + "hash": "4801AC89D71EFAF2244E4AB4D4EEBA43CE4D00DC1AA0F620E3CE1FC5C5B0E658", + "total": 1 + } + } + } + ], + "total_count": "45" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/blockchain_from_1_to_10.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/blockchain_from_1_to_10.json new file mode 100644 index 000000000..3eb4ef677 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/blockchain_from_1_to_10.json @@ -0,0 +1,369 @@ +{ + "id": "318f73b5-0fe6-43cc-935f-ef76f6c61cd4", + "jsonrpc": "2.0", + "result": { + "block_metas": [ + { + "block_id": { + "hash": "FCF9C2537FC3534CA71001FE1F14C4F769090948C1A521682F612E7CF73AE639", + "parts": { + "hash": "E16EDCB0EC135191F5C017FDF232967F50919E06B0F2F419FA93D006E606CF05", + "total": 1 + } + }, + "block_size": "569", + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "10", + "last_block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D", + "total": 1 + } + }, + "last_commit_hash": "E8DE5F9749FA5785B9B9F106C82233C910C75AE8A0903D1FAB146C1DD4E7A0EC", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:08.140032018Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + }, + { + "block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D", + "total": 1 + } + }, + "block_size": "571", + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "9", + "last_block_id": { + "hash": "875A50CDD812054D87A7F5CC6A0C7E224C6E2DF2F2A89EA51B9DCEE6136B469E", + "parts": { + "hash": "74F62C8CEF42AF0A685D84C8422751CD2269E16A793FAC95B96A8C42132E8338", + "total": 1 + } + }, + "last_commit_hash": "9EEDE09BD5848E1F97D54D4C2633582D152FEF610869E3D29815B5A2159D8631", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:07.619684947Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + }, + { + "block_id": { + "hash": "875A50CDD812054D87A7F5CC6A0C7E224C6E2DF2F2A89EA51B9DCEE6136B469E", + "parts": { + "hash": "74F62C8CEF42AF0A685D84C8422751CD2269E16A793FAC95B96A8C42132E8338", + "total": 1 + } + }, + "block_size": "569", + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "8", + "last_block_id": { + "hash": "29374DAF235CC5A1751E09A22DD6F200D1EA3BEB473A7820C4CC7F149DB032AB", + "parts": { + "hash": "7AEA98F9C8658AF6B5DE7B41AF0658AACBDC54D882E17BCFB35727B95EAD9E50", + "total": 1 + } + }, + "last_commit_hash": "6B184CC5107EAD2DD682BD3A1A60B568ECB9EE2A75DA34F237E42550B69E3146", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:07.101498447Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + }, + { + "block_id": { + "hash": "29374DAF235CC5A1751E09A22DD6F200D1EA3BEB473A7820C4CC7F149DB032AB", + "parts": { + "hash": "7AEA98F9C8658AF6B5DE7B41AF0658AACBDC54D882E17BCFB35727B95EAD9E50", + "total": 1 + } + }, + "block_size": "571", + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "7", + "last_block_id": { + "hash": "92DF7250265107D9FB3BAC7A97CA25AC2543B86E960632D11DDDE74FB5C2F41F", + "parts": { + "hash": "9F7DCBC5879343913CFAA6365B68E34FEA17CB1E1D1B7044ED72131D1F5DE9F9", + "total": 1 + } + }, + "last_commit_hash": "325A2D023AAA8705C2D9FF1593C8904EF16258825EC8212600BE98C69E20F3D2", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:06.580593612Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + }, + { + "block_id": { + "hash": "92DF7250265107D9FB3BAC7A97CA25AC2543B86E960632D11DDDE74FB5C2F41F", + "parts": { + "hash": "9F7DCBC5879343913CFAA6365B68E34FEA17CB1E1D1B7044ED72131D1F5DE9F9", + "total": 1 + } + }, + "block_size": "569", + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "6", + "last_block_id": { + "hash": "38070040A8D1365B66B0344664106193ECF1D18444A769E51D2881B15087DCD7", + "parts": { + "hash": "59876DFD84701B32F2AB5679D498E33A9AC26D11165B142D5E9EF3B2AF021BB9", + "total": 1 + } + }, + "last_commit_hash": "139381A60C8BCAF336ED8E8373FE52F7469DA76C054B9265921322046FD97B93", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:06.065052373Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + }, + { + "block_id": { + "hash": "38070040A8D1365B66B0344664106193ECF1D18444A769E51D2881B15087DCD7", + "parts": { + "hash": "59876DFD84701B32F2AB5679D498E33A9AC26D11165B142D5E9EF3B2AF021BB9", + "total": 1 + } + }, + "block_size": "571", + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "5", + "last_block_id": { + "hash": "7D162051AC61242B7613E085CA4E3488AE6A953E8BE3B72A9E6938E62F5212AF", + "parts": { + "hash": "D9A258567016DE8D364C0E64E3882C7DAD6488B129CE4612B3D67EBFF7CFF288", + "total": 1 + } + }, + "last_commit_hash": "4D95F1B754571826AA7C01E521D1D73A309880714C81DE48255DA2D57D55C756", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:05.545291963Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + }, + { + "block_id": { + "hash": "7D162051AC61242B7613E085CA4E3488AE6A953E8BE3B72A9E6938E62F5212AF", + "parts": { + "hash": "D9A258567016DE8D364C0E64E3882C7DAD6488B129CE4612B3D67EBFF7CFF288", + "total": 1 + } + }, + "block_size": "569", + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "4", + "last_block_id": { + "hash": "AFEB65E07422484A7295D2ABFEB66621386B98E8FC022B8BD177C14BDB4A3DB2", + "parts": { + "hash": "BC99391E5E093CEEE17A888CE4FA0E13BD06A0BA026336B662D445F5B1455DA9", + "total": 1 + } + }, + "last_commit_hash": "97FFFE3763FFAB168334C271B859483B95BF393CF4E61C91590CF3F6F55C4204", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:05.026580561Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + }, + { + "block_id": { + "hash": "AFEB65E07422484A7295D2ABFEB66621386B98E8FC022B8BD177C14BDB4A3DB2", + "parts": { + "hash": "BC99391E5E093CEEE17A888CE4FA0E13BD06A0BA026336B662D445F5B1455DA9", + "total": 1 + } + }, + "block_size": "571", + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "3", + "last_block_id": { + "hash": "618E263A7265C42E04D4C5DE3370F7B64C0AC8271435D17A20360C09A702E353", + "parts": { + "hash": "23296CEC8762B62711D174F14FFE5807F910AE3360F24BE55B58C1E8911FD01F", + "total": 1 + } + }, + "last_commit_hash": "7183ED105A3A3FF34CBAEB2CDCA13F3C3437EF0A140C40EABA425709AD44C066", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:04.508252675Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + }, + { + "block_id": { + "hash": "618E263A7265C42E04D4C5DE3370F7B64C0AC8271435D17A20360C09A702E353", + "parts": { + "hash": "23296CEC8762B62711D174F14FFE5807F910AE3360F24BE55B58C1E8911FD01F", + "total": 1 + } + }, + "block_size": "571", + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "2", + "last_block_id": { + "hash": "D55CD72165688BE21F2DF8C9AE46FA2BCA423223E99FC665DD2E621066F443C5", + "parts": { + "hash": "372520F1B93CD0EC3901006DE2E3CD752C9141628A7B430088DF912171355DDA", + "total": 1 + } + }, + "last_commit_hash": "48018604B85D54DC6E49DB6E4CF12F67FC56337B84E378AE2357B3E2CE4F1EC9", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:03.991666836Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + }, + { + "block_id": { + "hash": "D55CD72165688BE21F2DF8C9AE46FA2BCA423223E99FC665DD2E621066F443C5", + "parts": { + "hash": "372520F1B93CD0EC3901006DE2E3CD752C9141628A7B430088DF912171355DDA", + "total": 1 + } + }, + "block_size": "312", + "header": { + "app_hash": "", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "1", + "last_block_id": { + "hash": "", + "parts": { + "hash": "", + "total": 0 + } + }, + "last_commit_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:03.391799721Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "num_txs": "0" + } + ], + "last_height": "177" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/broadcast_tx_async.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/broadcast_tx_async.json new file mode 100644 index 000000000..c09dbb1f0 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/broadcast_tx_async.json @@ -0,0 +1,11 @@ +{ + "id": "58d2cc61-6e49-480a-9bc1-584f90203d4d", + "jsonrpc": "2.0", + "result": { + "code": 0, + "codespace": "", + "data": "", + "hash": "9F28904F9C0F3AB74A81CBA48E39124DA1C680B47FBFCBA0126870DB722BCC30", + "log": "" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/broadcast_tx_commit.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/broadcast_tx_commit.json new file mode 100644 index 000000000..5ebffd3b6 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/broadcast_tx_commit.json @@ -0,0 +1,82 @@ +{ + "id": "c1b2fe8d-ac41-4c65-aad1-15ff0b156fe1", + "jsonrpc": "2.0", + "result": { + "check_tx": { + "code": 0, + "codespace": "", + "data": null, + "events": [], + "gas_used": "0", + "gas_wanted": "1", + "info": "", + "log": "", + "mempoolError": "", + "priority": "0", + "sender": "" + }, + "deliver_tx": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "commit-key" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + }, + "hash": "D63F9C23791E610410B576D8C27BB5AEAC93CC1A58522428A7B32A1276085860", + "height": "48" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/broadcast_tx_sync.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/broadcast_tx_sync.json new file mode 100644 index 000000000..4c1874068 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/broadcast_tx_sync.json @@ -0,0 +1,11 @@ +{ + "id": "5daaaf5b-d964-4333-9866-9caab5c8efdc", + "jsonrpc": "2.0", + "result": { + "code": 0, + "codespace": "", + "data": "", + "hash": "57018296EE0919C9D351F2FFEA82A8D28DE223724D79965FC8D00A7477ED48BC", + "log": "" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/commit_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/commit_at_height_10.json new file mode 100644 index 000000000..0d75f9208 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/commit_at_height_10.json @@ -0,0 +1,53 @@ +{ + "id": "9493368d-025d-49b3-a3f8-486e55835e3a", + "jsonrpc": "2.0", + "result": { + "canonical": true, + "signed_header": { + "commit": { + "block_id": { + "hash": "FCF9C2537FC3534CA71001FE1F14C4F769090948C1A521682F612E7CF73AE639", + "parts": { + "hash": "E16EDCB0EC135191F5C017FDF232967F50919E06B0F2F419FA93D006E606CF05", + "total": 1 + } + }, + "height": "10", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "qJblJeAl6OtGRKkOa91+HLzX3ZGl/Nlnl5K9RiT2gRSPgPSjxq+95mSQSJ3b3I38mdZvYLUML6kEGvC/zjlJCQ==", + "timestamp": "2023-02-27T07:13:08.658439642Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + }, + "header": { + "app_hash": "0000000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "10", + "last_block_id": { + "hash": "9D9521F13DCA0C63C395F943F5A68B270A053B608145577F32907A70D8332E56", + "parts": { + "hash": "6760DBDF3B785148DB885DA08143118C6C30850995FF3C99E0A3303650E2430D", + "total": 1 + } + }, + "last_commit_hash": "E8DE5F9749FA5785B9B9F106C82233C910C75AE8A0903D1FAB146C1DD4E7A0EC", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:08.140032018Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + } + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/consensus_params.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/consensus_params.json new file mode 100644 index 000000000..970cd99d7 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/consensus_params.json @@ -0,0 +1,26 @@ +{ + "id": "6713de4d-11cc-4725-9dff-1dad524f2d44", + "jsonrpc": "2.0", + "result": { + "block_height": "10", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1" + }, + "evidence": { + "max_age_duration": "172800000000000", + "max_age_num_blocks": "100000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": { + "app": "0" + } + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/consensus_state.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/consensus_state.json new file mode 100644 index 000000000..05f3fc6f9 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/consensus_state.json @@ -0,0 +1,30 @@ +{ + "id": "d741eb15-a8cf-4b87-ae31-689ee9bcb1e2", + "jsonrpc": "2.0", + "result": { + "round_state": { + "height/round/step": "184/0/1", + "height_vote_set": [ + { + "precommits": [ + "nil-Vote" + ], + "precommits_bit_array": "BA{1:_} 0/10 = 0.00", + "prevotes": [ + "nil-Vote" + ], + "prevotes_bit_array": "BA{1:_} 0/10 = 0.00", + "round": 0 + } + ], + "locked_block_hash": "", + "proposal_block_hash": "", + "proposer": { + "address": "DD8A65495B6240145764A74E78CF203D51510371", + "index": 0 + }, + "start_time": "2023-02-27T07:14:38.877277579Z", + "valid_block_hash": "" + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/genesis.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/genesis.json new file mode 100644 index 000000000..f298ff2ec --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/genesis.json @@ -0,0 +1,42 @@ +{ + "id": "217c0860-637e-4368-9346-052ffbdee73c", + "jsonrpc": "2.0", + "result": { + "genesis": { + "app_hash": "", + "chain_id": "dockerchain", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1" + }, + "evidence": { + "max_age_duration": "172800000000000", + "max_age_num_blocks": "100000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": { + "app": "0" + } + }, + "genesis_time": "2023-02-27T07:13:03.391799721Z", + "initial_height": "1", + "validators": [ + { + "address": "DD8A65495B6240145764A74E78CF203D51510371", + "name": "", + "power": "10", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "OYpM2RXHEO1/R3jJRhAbjY8JhvjTBbiNJKBStEKu12s=" + } + } + ] + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/net_info.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/net_info.json new file mode 100644 index 000000000..2704a0dbf --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/net_info.json @@ -0,0 +1,12 @@ +{ + "id": "de1eb555-5788-4ee4-b263-a447ab6de53a", + "jsonrpc": "2.0", + "result": { + "listeners": [ + "Listener(@)" + ], + "listening": true, + "n_peers": "0", + "peers": [] + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/status.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/status.json new file mode 100644 index 000000000..07a144e9f --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/status.json @@ -0,0 +1,42 @@ +{ + "id": "d517d5b0-22de-4684-89ea-0d822293d7f6", + "jsonrpc": "2.0", + "result": { + "node_info": { + "channels": "40202122233038606100", + "id": "594d6b74ea5d99705f5cfbd28e20d937bda4c689", + "listen_addr": "tcp://0.0.0.0:26656", + "moniker": "dockernode", + "network": "dockerchain", + "other": { + "rpc_address": "tcp://0.0.0.0:26657", + "tx_index": "on" + }, + "protocol_version": { + "app": "1", + "block": "11", + "p2p": "8" + }, + "version": "0.37.0-alpha.3" + }, + "sync_info": { + "catching_up": false, + "earliest_app_hash": "", + "earliest_block_hash": "D55CD72165688BE21F2DF8C9AE46FA2BCA423223E99FC665DD2E621066F443C5", + "earliest_block_height": "1", + "earliest_block_time": "2023-02-27T07:13:03.391799721Z", + "latest_app_hash": "0600000000000000", + "latest_block_hash": "3CFC71BF78C7520A29378119AA39D0D585C75227E3B8EF8DCF19B4EB5CBF0E9A", + "latest_block_height": "53", + "latest_block_time": "2023-02-27T07:13:30.422625189Z" + }, + "validator_info": { + "address": "DD8A65495B6240145764A74E78CF203D51510371", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "OYpM2RXHEO1/R3jJRhAbjY8JhvjTBbiNJKBStEKu12s=" + }, + "voting_power": "10" + } + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_malformed.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_malformed.json new file mode 100644 index 000000000..c021fad1f --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_malformed.json @@ -0,0 +1,9 @@ +{ + "error": { + "code": -32603, + "data": "failed to parse query: \nparse error near PegText (line 1 symbol 2 - line 1 symbol 11):\n\"malformed\"\n", + "message": "Internal error" + }, + "id": "dc2d9ee9-e1f7-401d-b106-ed3b3b1fa24c", + "jsonrpc": "2.0" +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_0.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_0.json new file mode 100644 index 000000000..9e2f3ac83 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_0.json @@ -0,0 +1,73 @@ +{ + "id": "d7848eb8-b304-435e-b869-0dcb56fdf807", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/NewBlock", + "value": { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0600000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "56", + "last_block_id": { + "hash": "60C0B6596F4F7C591356C5137A6B703C57CF04D9BF9A01845EEE9E1AAF591A4C", + "parts": { + "hash": "A80BE8FE1D9C786A8C3ED5DA108D86041B139C381A71F88BA2AD0B4976B2ADAE", + "total": 1 + } + }, + "last_commit_hash": "2B22FC2C9495216758CCE6C2DD4F995E6972E0B106ACF4A03C8551AD4473786E", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:31.980620894Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "60C0B6596F4F7C591356C5137A6B703C57CF04D9BF9A01845EEE9E1AAF591A4C", + "parts": { + "hash": "A80BE8FE1D9C786A8C3ED5DA108D86041B139C381A71F88BA2AD0B4976B2ADAE", + "total": 1 + } + }, + "height": "55", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "k0/R5RXKtdQNqb+jO4Zg655dff4armOVI00upV0mlOyvxdo059HHEr6GZcWlwXZjtxntHgDMnR6R2C2YLc/HCw==", + "timestamp": "2023-02-27T07:13:31.980620894Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "result_begin_block": {}, + "result_end_block": { + "validator_updates": null + } + } + }, + "events": { + "tm.event": [ + "NewBlock" + ] + }, + "query": "tm.event = 'NewBlock'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_1.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_1.json new file mode 100644 index 000000000..a1e86951b --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_1.json @@ -0,0 +1,101 @@ +{ + "id": "d7848eb8-b304-435e-b869-0dcb56fdf807", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/NewBlock", + "value": { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0600000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "57", + "last_block_id": { + "hash": "7C88172D141FD038A4320E68F7B089A9669DE2E9A8FA62ED5037C0379437A9CF", + "parts": { + "hash": "33DE3DBBE54D0CCBE10CC16B63FD95DD737C1D1595FDDA142F8FF5E15E590256", + "total": 1 + } + }, + "last_commit_hash": "AD1F18EEC4FAE578CED2CA39C2119A22ED0C528F57F4BE25902A3923AE0722C7", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:32.50031582Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "7C88172D141FD038A4320E68F7B089A9669DE2E9A8FA62ED5037C0379437A9CF", + "parts": { + "hash": "33DE3DBBE54D0CCBE10CC16B63FD95DD737C1D1595FDDA142F8FF5E15E590256", + "total": 1 + } + }, + "height": "56", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "Gjt0bqP0wyIjCtzVcrQ1yA1OFcZQZUawFCKrBITjtCJeqDN3f5FUITe52Y6St6amM23zr18QObj/DeUAdt3DCA==", + "timestamp": "2023-02-27T07:13:32.50031582Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "result_begin_block": { + "events": [ + { + "type": "transfer", + "attributes": [ + { + "index": true, + "key": "recipient", + "value": "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta" + }, + { + "index": false, + "key": "sender", + "value": "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q" + } + ] + }, + { + "type": "message", + "attributes": [ + { + "index": true, + "key": "sender", + "value": "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q" + } + ] + } + ] + }, + "result_end_block": { + "validator_updates": null + } + } + }, + "events": { + "tm.event": [ + "NewBlock" + ] + }, + "query": "tm.event = 'NewBlock'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_2.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_2.json new file mode 100644 index 000000000..d7188e4c4 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_2.json @@ -0,0 +1,73 @@ +{ + "id": "d7848eb8-b304-435e-b869-0dcb56fdf807", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/NewBlock", + "value": { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0600000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "58", + "last_block_id": { + "hash": "953582B5F928C39F101565321CC67BC234733825A5563C6BD78B5A6F2569CFFD", + "parts": { + "hash": "8EA4905EB1D92878268729E8B9537611110C12A725FFE132094EA52E87DA188F", + "total": 1 + } + }, + "last_commit_hash": "A69B7992885ED130FED089E2C0D8C4EBD6D6AFE38836F9C6CA531AE3A423E6C1", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:33.01910569Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "953582B5F928C39F101565321CC67BC234733825A5563C6BD78B5A6F2569CFFD", + "parts": { + "hash": "8EA4905EB1D92878268729E8B9537611110C12A725FFE132094EA52E87DA188F", + "total": 1 + } + }, + "height": "57", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "a4ujPf5Q8b/bTM2AjRA1/TQC71Xse9kPBIHcITCiyoC24yb5azGGLrga/27+bglz0HJIMtKwumbLsKtG9sJjAA==", + "timestamp": "2023-02-27T07:13:33.01910569Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "result_begin_block": {}, + "result_end_block": { + "validator_updates": null + } + } + }, + "events": { + "tm.event": [ + "NewBlock" + ] + }, + "query": "tm.event = 'NewBlock'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_3.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_3.json new file mode 100644 index 000000000..fc0cd8fac --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_3.json @@ -0,0 +1,73 @@ +{ + "id": "d7848eb8-b304-435e-b869-0dcb56fdf807", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/NewBlock", + "value": { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0600000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "59", + "last_block_id": { + "hash": "5FEA892A1B3A0A0E8C123AE91EACABF28F6B3674EE00902FEDD24430D56B61BE", + "parts": { + "hash": "062F2511A22D89032C67D5ECEB5D99A1E4025581EB087C1F921F4EC6CFF7B103", + "total": 1 + } + }, + "last_commit_hash": "93E03808BBD103ADB03BD7BB511962F254B85FB548B0132FE43771E3A3C8EF48", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:33.537543698Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "5FEA892A1B3A0A0E8C123AE91EACABF28F6B3674EE00902FEDD24430D56B61BE", + "parts": { + "hash": "062F2511A22D89032C67D5ECEB5D99A1E4025581EB087C1F921F4EC6CFF7B103", + "total": 1 + } + }, + "height": "58", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "lrvMV2Z4GVXhb4E4szfmnwR8rUe6jTXjpDt9JMhvRJZfjTRV/RR3iMoM+4pKC0VJmlzU+fo0MDoRtu6OWBtqCg==", + "timestamp": "2023-02-27T07:13:33.537543698Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "result_begin_block": {}, + "result_end_block": { + "validator_updates": null + } + } + }, + "events": { + "tm.event": [ + "NewBlock" + ] + }, + "query": "tm.event = 'NewBlock'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_4.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_4.json new file mode 100644 index 000000000..edcf0c552 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_newblock_4.json @@ -0,0 +1,73 @@ +{ + "id": "d7848eb8-b304-435e-b869-0dcb56fdf807", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/NewBlock", + "value": { + "block": { + "data": { + "txs": [] + }, + "evidence": { + "evidence": [] + }, + "header": { + "app_hash": "0600000000000000", + "chain_id": "dockerchain", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "height": "60", + "last_block_id": { + "hash": "C3E86C7C298497DF7F36B148F9300F92691D426AEBD749EE25FA34488313EA3A", + "parts": { + "hash": "14217342A17F6A14185D85B7E2CFFE44CDC764FA38C5304E88D024E019C547BB", + "total": 1 + } + }, + "last_commit_hash": "39931C7A54AE3873B4457632A394894966A32A7A21596B7EE67F9EF72EF3022F", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "next_validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "proposer_address": "DD8A65495B6240145764A74E78CF203D51510371", + "time": "2023-02-27T07:13:34.057389794Z", + "validators_hash": "9815DD28ABEB04863FFC577AF32CF331ADEA96DC1BFD8ECCD1768BA36C15B362", + "version": { + "app": "1", + "block": "11" + } + }, + "last_commit": { + "block_id": { + "hash": "C3E86C7C298497DF7F36B148F9300F92691D426AEBD749EE25FA34488313EA3A", + "parts": { + "hash": "14217342A17F6A14185D85B7E2CFFE44CDC764FA38C5304E88D024E019C547BB", + "total": 1 + } + }, + "height": "59", + "round": 0, + "signatures": [ + { + "block_id_flag": 2, + "signature": "LvGGliJAHCHtcOhTxRFHokF6s+IXDv3HN9NzeJZP1FLdv+njqIhIBUrkpTF4lHGHNYequJB5VLE0Mim+lHf1BA==", + "timestamp": "2023-02-27T07:13:34.057389794Z", + "validator_address": "DD8A65495B6240145764A74E78CF203D51510371" + } + ] + } + }, + "result_begin_block": {}, + "result_end_block": { + "validator_updates": null + } + } + }, + "events": { + "tm.event": [ + "NewBlock" + ] + }, + "query": "tm.event = 'NewBlock'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs.json new file mode 100644 index 000000000..d15fc6188 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs.json @@ -0,0 +1,5 @@ +{ + "id": "f04f76fb-73bf-46c5-9151-4e7b089b73ed", + "jsonrpc": "2.0", + "result": {} +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_0.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_0.json new file mode 100644 index 000000000..16ae10509 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_0.json @@ -0,0 +1,97 @@ +{ + "id": "f04f76fb-73bf-46c5-9151-4e7b089b73ed", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/Tx", + "value": { + "TxResult": { + "height": "64", + "result": { + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx0" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ] + }, + "tx": "dHgwPXZhbHVl" + } + } + }, + "events": { + "app.creator": [ + "Cosmoshi Netowoko", + "Cosmoshi" + ], + "app.index_key": [ + "index is working", + "index is working" + ], + "app.key": [ + "tx0", + "value" + ], + "app.noindex_key": [ + "index is working", + "index is working" + ], + "tm.event": [ + "Tx" + ], + "tx.hash": [ + "FCB86F71C4EFF43E13C51FA12791F6DD1DDB8600A51131BE2289614D6882F6BE" + ], + "tx.height": [ + "64" + ] + }, + "query": "tm.event = 'Tx'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_1.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_1.json new file mode 100644 index 000000000..a90006a5d --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_1.json @@ -0,0 +1,97 @@ +{ + "id": "f04f76fb-73bf-46c5-9151-4e7b089b73ed", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/Tx", + "value": { + "TxResult": { + "height": "66", + "result": { + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx1" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ] + }, + "tx": "dHgxPXZhbHVl" + } + } + }, + "events": { + "app.creator": [ + "Cosmoshi Netowoko", + "Cosmoshi" + ], + "app.index_key": [ + "index is working", + "index is working" + ], + "app.key": [ + "tx1", + "value" + ], + "app.noindex_key": [ + "index is working", + "index is working" + ], + "tm.event": [ + "Tx" + ], + "tx.hash": [ + "9F424A8E634AAF63CFA61151A306AA788C9CC792F16B370F7867ED0BD972476C" + ], + "tx.height": [ + "66" + ] + }, + "query": "tm.event = 'Tx'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_2.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_2.json new file mode 100644 index 000000000..ce625ee44 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_2.json @@ -0,0 +1,97 @@ +{ + "id": "f04f76fb-73bf-46c5-9151-4e7b089b73ed", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/Tx", + "value": { + "TxResult": { + "height": "68", + "result": { + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx2" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ] + }, + "tx": "dHgyPXZhbHVl" + } + } + }, + "events": { + "app.creator": [ + "Cosmoshi Netowoko", + "Cosmoshi" + ], + "app.index_key": [ + "index is working", + "index is working" + ], + "app.key": [ + "tx2", + "value" + ], + "app.noindex_key": [ + "index is working", + "index is working" + ], + "tm.event": [ + "Tx" + ], + "tx.hash": [ + "C9D123E2CF19B9F0EC3CA1F64CD3BF0735397C84778B40B3EB5C49A752D53BF4" + ], + "tx.height": [ + "68" + ] + }, + "query": "tm.event = 'Tx'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_3.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_3.json new file mode 100644 index 000000000..84037a904 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_3.json @@ -0,0 +1,97 @@ +{ + "id": "f04f76fb-73bf-46c5-9151-4e7b089b73ed", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/Tx", + "value": { + "TxResult": { + "height": "70", + "result": { + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx3" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ] + }, + "tx": "dHgzPXZhbHVl" + } + } + }, + "events": { + "app.creator": [ + "Cosmoshi Netowoko", + "Cosmoshi" + ], + "app.index_key": [ + "index is working", + "index is working" + ], + "app.key": [ + "tx3", + "value" + ], + "app.noindex_key": [ + "index is working", + "index is working" + ], + "tm.event": [ + "Tx" + ], + "tx.hash": [ + "73117D6A783E4A37C1D9AD48744AD9FCC0D094C48AB8322FA11CD901C5174CFD" + ], + "tx.height": [ + "70" + ] + }, + "query": "tm.event = 'Tx'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_4.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_4.json new file mode 100644 index 000000000..20b0b1d6d --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_4.json @@ -0,0 +1,97 @@ +{ + "id": "f04f76fb-73bf-46c5-9151-4e7b089b73ed", + "jsonrpc": "2.0", + "result": { + "data": { + "type": "tendermint/event/Tx", + "value": { + "TxResult": { + "height": "72", + "result": { + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx4" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ] + }, + "tx": "dHg0PXZhbHVl" + } + } + }, + "events": { + "app.creator": [ + "Cosmoshi Netowoko", + "Cosmoshi" + ], + "app.index_key": [ + "index is working", + "index is working" + ], + "app.key": [ + "tx4", + "value" + ], + "app.noindex_key": [ + "index is working", + "index is working" + ], + "tm.event": [ + "Tx" + ], + "tx.hash": [ + "C349F213F04B4E8E749C6656E4C299E3BF22F4FAF141291A5C083336AD1A413B" + ], + "tx.height": [ + "72" + ] + }, + "query": "tm.event = 'Tx'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_0.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_0.json new file mode 100644 index 000000000..4314ab785 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_0.json @@ -0,0 +1,11 @@ +{ + "id": "cb942a83-32ad-4d23-aa91-86ef642f3816", + "jsonrpc": "2.0", + "result": { + "code": 0, + "codespace": "", + "data": "", + "hash": "FCB86F71C4EFF43E13C51FA12791F6DD1DDB8600A51131BE2289614D6882F6BE", + "log": "" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_1.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_1.json new file mode 100644 index 000000000..4e7cb7d3e --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_1.json @@ -0,0 +1,11 @@ +{ + "id": "c2ea2d7b-c121-4a8c-9bb9-98ff8a2f0a7e", + "jsonrpc": "2.0", + "result": { + "code": 0, + "codespace": "", + "data": "", + "hash": "9F424A8E634AAF63CFA61151A306AA788C9CC792F16B370F7867ED0BD972476C", + "log": "" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_2.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_2.json new file mode 100644 index 000000000..530214878 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_2.json @@ -0,0 +1,11 @@ +{ + "id": "e8b3d101-b2e7-4bd1-87d7-ec269a43ac39", + "jsonrpc": "2.0", + "result": { + "code": 0, + "codespace": "", + "data": "", + "hash": "C9D123E2CF19B9F0EC3CA1F64CD3BF0735397C84778B40B3EB5C49A752D53BF4", + "log": "" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_3.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_3.json new file mode 100644 index 000000000..3147f574a --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_3.json @@ -0,0 +1,11 @@ +{ + "id": "0877d6b8-2057-4bd1-a67e-8fe5be956598", + "jsonrpc": "2.0", + "result": { + "code": 0, + "codespace": "", + "data": "", + "hash": "73117D6A783E4A37C1D9AD48744AD9FCC0D094C48AB8322FA11CD901C5174CFD", + "log": "" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_4.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_4.json new file mode 100644 index 000000000..40642a38b --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_4.json @@ -0,0 +1,11 @@ +{ + "id": "66c13051-5981-4485-b5dc-28c59a1059a2", + "jsonrpc": "2.0", + "result": { + "code": 0, + "codespace": "", + "data": "", + "hash": "C349F213F04B4E8E749C6656E4C299E3BF22F4FAF141291A5C083336AD1A413B", + "log": "" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_5.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_5.json new file mode 100644 index 000000000..1d4e427db --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/subscribe_txs_broadcast_tx_5.json @@ -0,0 +1,11 @@ +{ + "id": "d24279ae-fa22-49ab-9e51-c68eab2fb289", + "jsonrpc": "2.0", + "result": { + "code": 0, + "codespace": "", + "data": "", + "hash": "CC4AC5C231481DD2ED2EA15789483B94565BF41612B6FEDE5BE7694F882CC202", + "log": "" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/tx_search_no_prove.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/tx_search_no_prove.json new file mode 100644 index 000000000..a0d4892a5 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/tx_search_no_prove.json @@ -0,0 +1,612 @@ +{ + "id": "8254b599-571a-4714-bdad-791d9d125a16", + "jsonrpc": "2.0", + "result": { + "total_count": "9", + "txs": [ + { + "hash": "9F28904F9C0F3AB74A81CBA48E39124DA1C680B47FBFCBA0126870DB722BCC30", + "height": "44", + "index": 0, + "tx": "YXN5bmMta2V5PXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "async-key" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "57018296EE0919C9D351F2FFEA82A8D28DE223724D79965FC8D00A7477ED48BC", + "height": "46", + "index": 0, + "tx": "c3luYy1rZXk9dmFsdWU=", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "sync-key" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "D63F9C23791E610410B576D8C27BB5AEAC93CC1A58522428A7B32A1276085860", + "height": "48", + "index": 0, + "tx": "Y29tbWl0LWtleT12YWx1ZQ==", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "commit-key" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "FCB86F71C4EFF43E13C51FA12791F6DD1DDB8600A51131BE2289614D6882F6BE", + "height": "64", + "index": 0, + "tx": "dHgwPXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx0" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "9F424A8E634AAF63CFA61151A306AA788C9CC792F16B370F7867ED0BD972476C", + "height": "66", + "index": 0, + "tx": "dHgxPXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx1" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "C9D123E2CF19B9F0EC3CA1F64CD3BF0735397C84778B40B3EB5C49A752D53BF4", + "height": "68", + "index": 0, + "tx": "dHgyPXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx2" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "73117D6A783E4A37C1D9AD48744AD9FCC0D094C48AB8322FA11CD901C5174CFD", + "height": "70", + "index": 0, + "tx": "dHgzPXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx3" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "C349F213F04B4E8E749C6656E4C299E3BF22F4FAF141291A5C083336AD1A413B", + "height": "72", + "index": 0, + "tx": "dHg0PXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx4" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "CC4AC5C231481DD2ED2EA15789483B94565BF41612B6FEDE5BE7694F882CC202", + "height": "74", + "index": 0, + "tx": "dHg1PXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx5" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + } + ] + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/incoming/tx_search_with_prove.json b/rpc/tests/kvstore_fixtures/v0_37/incoming/tx_search_with_prove.json new file mode 100644 index 000000000..4843e41de --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/incoming/tx_search_with_prove.json @@ -0,0 +1,702 @@ +{ + "id": "af0e742a-02d9-41e6-80ad-35d546e01190", + "jsonrpc": "2.0", + "result": { + "total_count": "9", + "txs": [ + { + "hash": "9F28904F9C0F3AB74A81CBA48E39124DA1C680B47FBFCBA0126870DB722BCC30", + "height": "44", + "index": 0, + "proof": { + "data": "YXN5bmMta2V5PXZhbHVl", + "proof": { + "aunts": [], + "index": "0", + "leaf_hash": "MIH5kVBA0TizrX+JVzLSdnwp6Ful2EOI0E4XpdgmK3o=", + "total": "1" + }, + "root_hash": "3081F9915040D138B3AD7F895732D2767C29E85BA5D84388D04E17A5D8262B7A" + }, + "tx": "YXN5bmMta2V5PXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "async-key" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "57018296EE0919C9D351F2FFEA82A8D28DE223724D79965FC8D00A7477ED48BC", + "height": "46", + "index": 0, + "proof": { + "data": "c3luYy1rZXk9dmFsdWU=", + "proof": { + "aunts": [], + "index": "0", + "leaf_hash": "oL+OYRo6LtD+lKo0W5A2kcPlbt4Of3c/VN57Ag54iEk=", + "total": "1" + }, + "root_hash": "A0BF8E611A3A2ED0FE94AA345B903691C3E56EDE0E7F773F54DE7B020E788849" + }, + "tx": "c3luYy1rZXk9dmFsdWU=", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "sync-key" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "D63F9C23791E610410B576D8C27BB5AEAC93CC1A58522428A7B32A1276085860", + "height": "48", + "index": 0, + "proof": { + "data": "Y29tbWl0LWtleT12YWx1ZQ==", + "proof": { + "aunts": [], + "index": "0", + "leaf_hash": "wq4Wy/oF+/0xsH+eJq1SqY2BgYS2FVXbLAXNcCLkB74=", + "total": "1" + }, + "root_hash": "C2AE16CBFA05FBFD31B07F9E26AD52A98D818184B61555DB2C05CD7022E407BE" + }, + "tx": "Y29tbWl0LWtleT12YWx1ZQ==", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "commit-key" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "FCB86F71C4EFF43E13C51FA12791F6DD1DDB8600A51131BE2289614D6882F6BE", + "height": "64", + "index": 0, + "proof": { + "data": "dHgwPXZhbHVl", + "proof": { + "aunts": [], + "index": "0", + "leaf_hash": "3UnhxGnCw+sKtov5uD2YZbCP79vHFwLMc1ZPTaVocKQ=", + "total": "1" + }, + "root_hash": "DD49E1C469C2C3EB0AB68BF9B83D9865B08FEFDBC71702CC73564F4DA56870A4" + }, + "tx": "dHgwPXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx0" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "9F424A8E634AAF63CFA61151A306AA788C9CC792F16B370F7867ED0BD972476C", + "height": "66", + "index": 0, + "proof": { + "data": "dHgxPXZhbHVl", + "proof": { + "aunts": [], + "index": "0", + "leaf_hash": "QnwQk7ERU9NjeD1GlLa4H8lscIRFD3evj6SZulKp3T8=", + "total": "1" + }, + "root_hash": "427C1093B11153D363783D4694B6B81FC96C7084450F77AF8FA499BA52A9DD3F" + }, + "tx": "dHgxPXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx1" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "C9D123E2CF19B9F0EC3CA1F64CD3BF0735397C84778B40B3EB5C49A752D53BF4", + "height": "68", + "index": 0, + "proof": { + "data": "dHgyPXZhbHVl", + "proof": { + "aunts": [], + "index": "0", + "leaf_hash": "0eF/BEMF82Y/mIMIM0HX/isU2jI44Z2rAor5MA0PrKM=", + "total": "1" + }, + "root_hash": "D1E17F044305F3663F9883083341D7FE2B14DA3238E19DAB028AF9300D0FACA3" + }, + "tx": "dHgyPXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx2" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "73117D6A783E4A37C1D9AD48744AD9FCC0D094C48AB8322FA11CD901C5174CFD", + "height": "70", + "index": 0, + "proof": { + "data": "dHgzPXZhbHVl", + "proof": { + "aunts": [], + "index": "0", + "leaf_hash": "jt+3kmBnxAUZK7c0gytFbKegUaR38TB3aAlKsIZ0RNU=", + "total": "1" + }, + "root_hash": "8EDFB7926067C405192BB734832B456CA7A051A477F1307768094AB0867444D5" + }, + "tx": "dHgzPXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx3" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "C349F213F04B4E8E749C6656E4C299E3BF22F4FAF141291A5C083336AD1A413B", + "height": "72", + "index": 0, + "proof": { + "data": "dHg0PXZhbHVl", + "proof": { + "aunts": [], + "index": "0", + "leaf_hash": "oZPOdbpVGhDcNY2OaPjybbnfL2SMaDmXm9ufOgruPCA=", + "total": "1" + }, + "root_hash": "A193CE75BA551A10DC358D8E68F8F26DB9DF2F648C6839979BDB9F3A0AEE3C20" + }, + "tx": "dHg0PXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx4" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + }, + { + "hash": "CC4AC5C231481DD2ED2EA15789483B94565BF41612B6FEDE5BE7694F882CC202", + "height": "74", + "index": 0, + "proof": { + "data": "dHg1PXZhbHVl", + "proof": { + "aunts": [], + "index": "0", + "leaf_hash": "53wfU57GnWQ6Q46hc19t7bxY7SaY7WD4T6fy+TOPizM=", + "total": "1" + }, + "root_hash": "E77C1F539EC69D643A438EA1735F6DEDBC58ED2698ED60F84FA7F2F9338F8B33" + }, + "tx": "dHg1PXZhbHVl", + "tx_result": { + "code": 0, + "codespace": "", + "data": null, + "events": [ + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi Netowoko" + }, + { + "index": true, + "key": "key", + "value": "tx5" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + }, + { + "attributes": [ + { + "index": true, + "key": "creator", + "value": "Cosmoshi" + }, + { + "index": true, + "key": "key", + "value": "value" + }, + { + "index": true, + "key": "index_key", + "value": "index is working" + }, + { + "index": false, + "key": "noindex_key", + "value": "index is working" + } + ], + "type": "app" + } + ], + "gas_used": "0", + "gas_wanted": "0", + "info": "", + "log": "" + } + } + ] + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/abci_info.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/abci_info.json new file mode 100644 index 000000000..c49d71f05 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/abci_info.json @@ -0,0 +1,6 @@ +{ + "id": "4e158c90-577c-4408-b8f6-d3680b84e7e9", + "jsonrpc": "2.0", + "method": "abci_info", + "params": null +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/abci_query_with_existing_key.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/abci_query_with_existing_key.json new file mode 100644 index 000000000..94c2fb2ab --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/abci_query_with_existing_key.json @@ -0,0 +1,8 @@ +{ + "id": "4c088a2c-e01c-4d8b-aadc-009753b68d04", + "jsonrpc": "2.0", + "method": "abci_query", + "params": { + "data": "747830" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/abci_query_with_non_existent_key.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/abci_query_with_non_existent_key.json new file mode 100644 index 000000000..d24a8065e --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/abci_query_with_non_existent_key.json @@ -0,0 +1,8 @@ +{ + "id": "437f6c65-b4b2-4417-9e03-2b584a75403f", + "jsonrpc": "2.0", + "method": "abci_query", + "params": { + "data": "6e6f6e5f6578697374656e745f6b6579" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_at_height_0.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_at_height_0.json new file mode 100644 index 000000000..266523e62 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_at_height_0.json @@ -0,0 +1,8 @@ +{ + "id": "c1144ac0-8c4d-46cc-9430-8c14c598a029", + "jsonrpc": "2.0", + "method": "block", + "params": { + "height": "0" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_at_height_1.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_at_height_1.json new file mode 100644 index 000000000..47f5da6f6 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_at_height_1.json @@ -0,0 +1,8 @@ +{ + "id": "5f66ff6f-8283-4c9a-8437-b120248182d8", + "jsonrpc": "2.0", + "method": "block", + "params": { + "height": "1" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_at_height_10.json new file mode 100644 index 000000000..0f2787c61 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_at_height_10.json @@ -0,0 +1,8 @@ +{ + "id": "a24afd41-dbab-453d-8734-f599f84eb653", + "jsonrpc": "2.0", + "method": "block", + "params": { + "height": "10" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_by_hash.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_by_hash.json new file mode 100644 index 000000000..d11fb8dd4 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_by_hash.json @@ -0,0 +1,8 @@ +{ + "id": "56d4851a-1f30-4d73-9f86-c1a084e8aa97", + "jsonrpc": "2.0", + "method": "block_by_hash", + "params": { + "hash": "/PnCU3/DU0ynEAH+HxTE92kJCUjBpSFoL2EufPc65jk=" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_results_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_results_at_height_10.json new file mode 100644 index 000000000..2d8a50195 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_results_at_height_10.json @@ -0,0 +1,8 @@ +{ + "id": "77cfdbe4-630e-4b73-b30d-90a1236f96a3", + "jsonrpc": "2.0", + "method": "block_results", + "params": { + "height": "10" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_search.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_search.json new file mode 100644 index 000000000..63b995b4c --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/block_search.json @@ -0,0 +1,11 @@ +{ + "id": "60d0e76b-d645-4b37-adc0-42fc0fa7d394", + "jsonrpc": "2.0", + "method": "block_search", + "params": { + "order_by": "asc", + "page": "1", + "per_page": "100", + "query": "block.height > 1" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/blockchain_from_1_to_10.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/blockchain_from_1_to_10.json new file mode 100644 index 000000000..d5fe40e70 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/blockchain_from_1_to_10.json @@ -0,0 +1,9 @@ +{ + "id": "318f73b5-0fe6-43cc-935f-ef76f6c61cd4", + "jsonrpc": "2.0", + "method": "blockchain", + "params": { + "maxHeight": "10", + "minHeight": "1" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/broadcast_tx_async.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/broadcast_tx_async.json new file mode 100644 index 000000000..939bc8c1d --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/broadcast_tx_async.json @@ -0,0 +1,8 @@ +{ + "id": "adb67e95-0d9f-40ed-8e24-6b9b537107b3", + "jsonrpc": "2.0", + "method": "broadcast_tx_async", + "params": { + "tx": "YXN5bmMta2V5PXZhbHVl" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/broadcast_tx_commit.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/broadcast_tx_commit.json new file mode 100644 index 000000000..c1be9b0af --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/broadcast_tx_commit.json @@ -0,0 +1,8 @@ +{ + "id": "c1b2fe8d-ac41-4c65-aad1-15ff0b156fe1", + "jsonrpc": "2.0", + "method": "broadcast_tx_commit", + "params": { + "tx": "Y29tbWl0LWtleT12YWx1ZQ==" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/broadcast_tx_sync.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/broadcast_tx_sync.json new file mode 100644 index 000000000..3a488a2b0 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/broadcast_tx_sync.json @@ -0,0 +1,8 @@ +{ + "id": "5daaaf5b-d964-4333-9866-9caab5c8efdc", + "jsonrpc": "2.0", + "method": "broadcast_tx_sync", + "params": { + "tx": "c3luYy1rZXk9dmFsdWU=" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/commit_at_height_10.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/commit_at_height_10.json new file mode 100644 index 000000000..16f63f423 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/commit_at_height_10.json @@ -0,0 +1,8 @@ +{ + "id": "9493368d-025d-49b3-a3f8-486e55835e3a", + "jsonrpc": "2.0", + "method": "commit", + "params": { + "height": "10" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/consensus_params.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/consensus_params.json new file mode 100644 index 000000000..52b0740e5 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/consensus_params.json @@ -0,0 +1,8 @@ +{ + "id": "6713de4d-11cc-4725-9dff-1dad524f2d44", + "jsonrpc": "2.0", + "method": "consensus_params", + "params": { + "height": "10" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/consensus_state.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/consensus_state.json new file mode 100644 index 000000000..f82b4261e --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/consensus_state.json @@ -0,0 +1,6 @@ +{ + "id": "d741eb15-a8cf-4b87-ae31-689ee9bcb1e2", + "jsonrpc": "2.0", + "method": "consensus_state", + "params": null +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/genesis.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/genesis.json new file mode 100644 index 000000000..89ba435aa --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/genesis.json @@ -0,0 +1,6 @@ +{ + "id": "217c0860-637e-4368-9346-052ffbdee73c", + "jsonrpc": "2.0", + "method": "genesis", + "params": null +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/net_info.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/net_info.json new file mode 100644 index 000000000..b13f6ea25 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/net_info.json @@ -0,0 +1,6 @@ +{ + "id": "de1eb555-5788-4ee4-b263-a447ab6de53a", + "jsonrpc": "2.0", + "method": "net_info", + "params": null +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/status.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/status.json new file mode 100644 index 000000000..a0b375870 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/status.json @@ -0,0 +1,6 @@ +{ + "id": "d517d5b0-22de-4684-89ea-0d822293d7f6", + "jsonrpc": "2.0", + "method": "status", + "params": null +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_malformed.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_malformed.json new file mode 100644 index 000000000..c36834f7e --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_malformed.json @@ -0,0 +1,8 @@ +{ + "id": "505651d8-1cf4-4bdd-b58f-0c66360640b5", + "jsonrpc": "2.0", + "method": "subscribe", + "params": { + "query": "malformed query" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_newblock.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_newblock.json new file mode 100644 index 000000000..9e713a5f9 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_newblock.json @@ -0,0 +1,8 @@ +{ + "id": "c5fff7c8-1aca-40a3-a4d1-a55bb1e62327", + "jsonrpc": "2.0", + "method": "subscribe", + "params": { + "query": "tm.event = 'NewBlock'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs.json new file mode 100644 index 000000000..0b3d2fc9c --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs.json @@ -0,0 +1,8 @@ +{ + "id": "580dab68-e0de-4a58-85cf-9a56120796d1", + "jsonrpc": "2.0", + "method": "subscribe", + "params": { + "query": "tm.event = 'Tx'" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_0.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_0.json new file mode 100644 index 000000000..95fe89f77 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_0.json @@ -0,0 +1,8 @@ +{ + "id": "cb942a83-32ad-4d23-aa91-86ef642f3816", + "jsonrpc": "2.0", + "method": "broadcast_tx_async", + "params": { + "tx": "dHgwPXZhbHVl" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_1.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_1.json new file mode 100644 index 000000000..b91d73b5b --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_1.json @@ -0,0 +1,8 @@ +{ + "id": "c2ea2d7b-c121-4a8c-9bb9-98ff8a2f0a7e", + "jsonrpc": "2.0", + "method": "broadcast_tx_async", + "params": { + "tx": "dHgxPXZhbHVl" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_2.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_2.json new file mode 100644 index 000000000..0d1fd7d30 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_2.json @@ -0,0 +1,8 @@ +{ + "id": "e8b3d101-b2e7-4bd1-87d7-ec269a43ac39", + "jsonrpc": "2.0", + "method": "broadcast_tx_async", + "params": { + "tx": "dHgyPXZhbHVl" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_3.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_3.json new file mode 100644 index 000000000..53d18a845 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_3.json @@ -0,0 +1,8 @@ +{ + "id": "0877d6b8-2057-4bd1-a67e-8fe5be956598", + "jsonrpc": "2.0", + "method": "broadcast_tx_async", + "params": { + "tx": "dHgzPXZhbHVl" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_4.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_4.json new file mode 100644 index 000000000..50e86e9c5 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_4.json @@ -0,0 +1,8 @@ +{ + "id": "66c13051-5981-4485-b5dc-28c59a1059a2", + "jsonrpc": "2.0", + "method": "broadcast_tx_async", + "params": { + "tx": "dHg0PXZhbHVl" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_5.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_5.json new file mode 100644 index 000000000..83c91aece --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/subscribe_txs_broadcast_tx_5.json @@ -0,0 +1,8 @@ +{ + "id": "d24279ae-fa22-49ab-9e51-c68eab2fb289", + "jsonrpc": "2.0", + "method": "broadcast_tx_async", + "params": { + "tx": "dHg1PXZhbHVl" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/tx_search_no_prove.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/tx_search_no_prove.json new file mode 100644 index 000000000..c43385554 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/tx_search_no_prove.json @@ -0,0 +1,12 @@ +{ + "id": "8254b599-571a-4714-bdad-791d9d125a16", + "jsonrpc": "2.0", + "method": "tx_search", + "params": { + "order_by": "asc", + "page": "1", + "per_page": "10", + "prove": false, + "query": "tx.height > 1" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/v0_37/outgoing/tx_search_with_prove.json b/rpc/tests/kvstore_fixtures/v0_37/outgoing/tx_search_with_prove.json new file mode 100644 index 000000000..374ec16b7 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/v0_37/outgoing/tx_search_with_prove.json @@ -0,0 +1,12 @@ +{ + "id": "af0e742a-02d9-41e6-80ad-35d546e01190", + "jsonrpc": "2.0", + "method": "tx_search", + "params": { + "order_by": "asc", + "page": "1", + "per_page": "10", + "prove": true, + "query": "tx.height > 1" + } +} \ No newline at end of file diff --git a/rpc/tests/simd_fixtures/incoming/tx_search.json b/rpc/tests/simd_fixtures/incoming/tx_search.json new file mode 100644 index 000000000..0bbf8c6d5 --- /dev/null +++ b/rpc/tests/simd_fixtures/incoming/tx_search.json @@ -0,0 +1,166 @@ +{ + "jsonrpc": "2.0", + "id": "950dbe9e-8991-4680-b990-ac5cbe1cf9b5", + "result": { + "txs": [ + { + "hash": "ACDCA9995210D86AF9C73535047AAA3469E915C548194423279FE5F61E41E9F8", + "height": "925", + "index": 0, + "tx_result": { + "code": 0, + "data": "Ei0KKy9pYmMuY29yZS5jbGllbnQudjEuTXNnQ3JlYXRlQ2xpZW50UmVzcG9uc2U=", + "log": "[{\"msg_index\":0,\"events\":[{\"type\":\"create_client\",\"attributes\":[{\"key\":\"client_id\",\"value\":\"07-tendermint-17\"},{\"key\":\"client_type\",\"value\":\"07-tendermint\"},{\"key\":\"consensus_height\",\"value\":\"1-924\"}]},{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"/ibc.core.client.v1.MsgCreateClient\"},{\"key\":\"sender\",\"value\":\"cosmos175gsvrtdqe5j77566dfyf8f2pgle5v5u9xsda9\"},{\"key\":\"module\",\"value\":\"ibc_client\"}]}]}]", + "info": "", + "gas_wanted": "88080", + "gas_used": "79943", + "events": [ + { + "type": "coin_spent", + "attributes": [ + { + "key": "spender", + "value": "cosmos175gsvrtdqe5j77566dfyf8f2pgle5v5u9xsda9", + "index": true + }, + { + "key": "amount", + "value": "881stake", + "index": true + } + ] + }, + { + "type": "coin_received", + "attributes": [ + { + "key": "receiver", + "value": "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta", + "index": true + }, + { + "key": "amount", + "value": "881stake", + "index": true + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta", + "index": true + }, + { + "key": "sender", + "value": "cosmos175gsvrtdqe5j77566dfyf8f2pgle5v5u9xsda9", + "index": true + }, + { + "key": "amount", + "value": "881stake", + "index": true + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos175gsvrtdqe5j77566dfyf8f2pgle5v5u9xsda9", + "index": true + } + ] + }, + { + "type": "tx", + "attributes": [ + { + "key": "fee", + "value": "881stake", + "index": true + }, + { + "key": "fee_payer", + "value": "cosmos175gsvrtdqe5j77566dfyf8f2pgle5v5u9xsda9", + "index": true + } + ] + }, + { + "type": "tx", + "attributes": [ + { + "key": "acc_seq", + "value": "cosmos175gsvrtdqe5j77566dfyf8f2pgle5v5u9xsda9/17", + "index": true + } + ] + }, + { + "type": "tx", + "attributes": [ + { + "key": "signature", + "value": "eaw7VwfoviJhMffnwxld3T4CR3o1SSZRaLvXldmZ9X5Ktzfegqb5kOKDZWjLPNh1szOiq7/umSm3kuRZNjZEeA==", + "index": true + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "/ibc.core.client.v1.MsgCreateClient", + "index": true + }, + { + "key": "sender", + "value": "cosmos175gsvrtdqe5j77566dfyf8f2pgle5v5u9xsda9", + "index": true + } + ] + }, + { + "type": "create_client", + "attributes": [ + { + "key": "client_id", + "value": "07-tendermint-17", + "index": true + }, + { + "key": "client_type", + "value": "07-tendermint", + "index": true + }, + { + "key": "consensus_height", + "value": "1-924", + "index": true + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "module", + "value": "ibc_client", + "index": true + } + ] + } + ], + "codespace": "" + }, + "tx": "Cs8DCo0DCiMvaWJjLmNvcmUuY2xpZW50LnYxLk1zZ0NyZWF0ZUNsaWVudBLlAgqqAQorL2liYy5saWdodGNsaWVudHMudGVuZGVybWludC52MS5DbGllbnRTdGF0ZRJ7CgVpYmMtMRIECAEQAxoECIDqSSIECIDfbioCCCgyADoFCAEQnAdCGQoJCAEYASABKgEAEgwKAgABECEYBCAMMAFCGQoJCAEYASABKgEAEgwKAgABECAYASABMAFKB3VwZ3JhZGVKEHVwZ3JhZGVkSUJDU3RhdGVQAVgBEoYBCi4vaWJjLmxpZ2h0Y2xpZW50cy50ZW5kZXJtaW50LnYxLkNvbnNlbnN1c1N0YXRlElQKDAj2kMWeBhD4iszpARIiCiBZ4RxJoGp5+LiWhv9GmXmro0O9PsLAJae7p+ddjMlKshogtvCuWO8lJ8lFLlabtOVGzd/+1IblTmo12leDMLoFz/saLWNvc21vczE3NWdzdnJ0ZHFlNWo3NzU2NmRmeWY4ZjJwZ2xlNXY1dTl4c2RhORI9aGVybWVzIDEuMi4wKzdmM2M0ZDc4LWRpcnR5IChodHRwczovL2hlcm1lcy5pbmZvcm1hbC5zeXN0ZW1zKRJmClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiED3b32P6jgs4E32s/TRZksqUTo3E7SuAcQOsAGQ5UYWjQSBAoCCAEYERISCgwKBXN0YWtlEgM4ODEQkLAFGkB5rDtXB+i+ImEx9+fDGV3dPgJHejVJJlFou9eV2Zn1fkq3N96CpvmQ4oNlaMs82HWzM6Krv+6ZKbeS5Fk2NkR4" + } + ], + "total_count": "1" + } +} \ No newline at end of file diff --git a/tendermint/src/abci.rs b/tendermint/src/abci.rs index 2ea41b9d9..72a179ff7 100644 --- a/tendermint/src/abci.rs +++ b/tendermint/src/abci.rs @@ -44,12 +44,15 @@ pub mod request; pub mod response; pub mod types; +pub use crate::v0_37::abci::request::Request; +pub use crate::v0_37::abci::response::Response; + pub use event::{Event, EventAttribute, EventAttributeIndexExt}; #[doc(inline)] pub use self::{ code::Code, kind::MethodKind, - request::{ConsensusRequest, InfoRequest, MempoolRequest, Request, SnapshotRequest}, - response::{ConsensusResponse, InfoResponse, MempoolResponse, Response, SnapshotResponse}, + request::{ConsensusRequest, InfoRequest, MempoolRequest, SnapshotRequest}, + response::{ConsensusResponse, InfoResponse, MempoolResponse, SnapshotResponse}, }; diff --git a/tendermint/src/abci/doc/request-applysnapshotchunk.md b/tendermint/src/abci/doc/request-applysnapshotchunk.md index fe1c35598..d79d42e57 100644 --- a/tendermint/src/abci/doc/request-applysnapshotchunk.md +++ b/tendermint/src/abci/doc/request-applysnapshotchunk.md @@ -5,7 +5,7 @@ appropriate. Tendermint will not do this unless instructed by the application. The application may want to verify each chunk, e.g., by attaching chunk -hashes in [`Snapshot::metadata`] and/or incrementally verifying contents +hashes in `Snapshot::metadata` and/or incrementally verifying contents against `app_hash`. When all chunks have been accepted, Tendermint will make an ABCI [`Info`] @@ -18,4 +18,4 @@ because no suitable peers are available), it will reject the snapshot and try a different one via `OfferSnapshot`. The application should be prepared to reset and accept it or abort as appropriate. -[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#applysnapshotchunk) \ No newline at end of file +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#applysnapshotchunk) diff --git a/tendermint/src/abci/doc/request-offersnapshot.md b/tendermint/src/abci/doc/request-offersnapshot.md index db0e60b17..41303e0d9 100644 --- a/tendermint/src/abci/doc/request-offersnapshot.md +++ b/tendermint/src/abci/doc/request-offersnapshot.md @@ -13,8 +13,8 @@ additional verification schemes to avoid denial-of-service attacks. The verified `app_hash` is automatically checked against the restored application at the end of snapshot restoration. -See also the [`Snapshot`] data type and the [ABCI state sync documentation][ssd]. +See also the `Snapshot` data type and the [ABCI state sync documentation][ssd]. [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#offersnapshot) -[ssd]: https://docs.tendermint.com/master/spec/abci/apps.html#state-sync \ No newline at end of file +[ssd]: https://docs.tendermint.com/master/spec/abci/apps.html#state-sync diff --git a/tendermint/src/abci/doc/request-prepareproposal.md b/tendermint/src/abci/doc/request-prepareproposal.md new file mode 100644 index 000000000..d977f1758 --- /dev/null +++ b/tendermint/src/abci/doc/request-prepareproposal.md @@ -0,0 +1 @@ +[ABCI documentation](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/abci/abci++_methods.md#prepareproposal) diff --git a/tendermint/src/abci/doc/request-processproposal.md b/tendermint/src/abci/doc/request-processproposal.md new file mode 100644 index 000000000..1d32bf046 --- /dev/null +++ b/tendermint/src/abci/doc/request-processproposal.md @@ -0,0 +1 @@ +[ABCI documentation](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/abci/abci++_methods.md#processproposal) diff --git a/tendermint/src/abci/doc/response-offersnapshot.md b/tendermint/src/abci/doc/response-offersnapshot.md index 0da7a66fa..42f0d076c 100644 --- a/tendermint/src/abci/doc/response-offersnapshot.md +++ b/tendermint/src/abci/doc/response-offersnapshot.md @@ -1,7 +1,7 @@ Returns the application's response to a snapshot offer. -See also the [`Snapshot`] data type and the [ABCI state sync documentation][ssd]. +See also the [`OfferSnapshot`] data type and the [ABCI state sync documentation][ssd]. [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#offersnapshot) -[ssd]: https://docs.tendermint.com/master/spec/abci/apps.html#state-sync \ No newline at end of file +[ssd]: https://docs.tendermint.com/master/spec/abci/apps.html#state-sync diff --git a/tendermint/src/abci/doc/response-prepareproposal.md b/tendermint/src/abci/doc/response-prepareproposal.md new file mode 100644 index 000000000..d977f1758 --- /dev/null +++ b/tendermint/src/abci/doc/response-prepareproposal.md @@ -0,0 +1 @@ +[ABCI documentation](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/abci/abci++_methods.md#prepareproposal) diff --git a/tendermint/src/abci/doc/response-processproposal.md b/tendermint/src/abci/doc/response-processproposal.md new file mode 100644 index 000000000..1d32bf046 --- /dev/null +++ b/tendermint/src/abci/doc/response-processproposal.md @@ -0,0 +1 @@ +[ABCI documentation](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/abci/abci++_methods.md#processproposal) diff --git a/tendermint/src/abci/event.rs b/tendermint/src/abci/event.rs index 8b69ba2ff..04c4baa65 100644 --- a/tendermint/src/abci/event.rs +++ b/tendermint/src/abci/event.rs @@ -1,7 +1,6 @@ -use serde::{Deserialize, Serialize}; +use serde::Serialize; use crate::prelude::*; -use crate::serializers::bytes::base64string; /// An event that occurred while processing a request. /// @@ -13,13 +12,12 @@ use crate::serializers::bytes::base64string; /// be queried using these events. /// /// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#events) -#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub struct Event { /// The kind of event. /// /// Tendermint calls this the `type`, but we use `kind` to avoid confusion /// with Rust types and follow Rust conventions. - #[serde(rename = "type")] pub kind: String, /// A list of [`EventAttribute`]s describing the event. pub attributes: Vec, @@ -63,19 +61,11 @@ impl Event { /// [`Event::new`] for details. /// /// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#events) -#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub struct EventAttribute { /// The event key. - #[serde( - serialize_with = "base64string::serialize", - deserialize_with = "base64string::deserialize_to_string" - )] pub key: String, /// The event value. - #[serde( - serialize_with = "base64string::serialize", - deserialize_with = "base64string::deserialize_to_string" - )] pub value: String, /// Whether Tendermint's indexer should index this event. /// @@ -139,59 +129,124 @@ impl, V: Into> From<(K, V)> for EventAttribute { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; +mod v0_34 { + use super::{Event, EventAttribute}; + use crate::prelude::*; + use core::convert::{TryFrom, TryInto}; + + use tendermint_proto::v0_34::abci as pb; + use tendermint_proto::Protobuf; + + impl From for pb::EventAttribute { + fn from(event: EventAttribute) -> Self { + Self { + key: event.key.into(), + value: event.value.into(), + index: event.index, + } + } + } -use tendermint_proto::{abci as pb, Protobuf}; + impl TryFrom for EventAttribute { + type Error = crate::Error; + + fn try_from(event: pb::EventAttribute) -> Result { + // We insist that keys and values are strings, like tm 0.35 did. + Ok(Self { + key: String::from_utf8(event.key.to_vec()) + .map_err(|e| crate::Error::parse(e.to_string()))?, + value: String::from_utf8(event.value.to_vec()) + .map_err(|e| crate::Error::parse(e.to_string()))?, + index: event.index, + }) + } + } -impl From for pb::EventAttribute { - fn from(event: EventAttribute) -> Self { - Self { - key: event.key.into(), - value: event.value.into(), - index: event.index, + impl Protobuf for EventAttribute {} + + impl From for pb::Event { + fn from(event: Event) -> Self { + Self { + r#type: event.kind, + attributes: event.attributes.into_iter().map(Into::into).collect(), + } } } -} -impl TryFrom for EventAttribute { - type Error = crate::Error; - - fn try_from(event: pb::EventAttribute) -> Result { - // We insist that keys and values are strings, like tm 0.35 did. - Ok(Self { - key: String::from_utf8(event.key.to_vec()) - .map_err(|e| crate::Error::parse(e.to_string()))?, - value: String::from_utf8(event.value.to_vec()) - .map_err(|e| crate::Error::parse(e.to_string()))?, - index: event.index, - }) + impl TryFrom for Event { + type Error = crate::Error; + + fn try_from(event: pb::Event) -> Result { + Ok(Self { + kind: event.r#type, + attributes: event + .attributes + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } } + + impl Protobuf for Event {} } -impl Protobuf for EventAttribute {} +mod v0_37 { + use super::{Event, EventAttribute}; + use crate::prelude::*; + use core::convert::{TryFrom, TryInto}; + + use tendermint_proto::v0_37::abci as pb; + use tendermint_proto::Protobuf; + + impl From for pb::EventAttribute { + fn from(event: EventAttribute) -> Self { + Self { + key: event.key, + value: event.value, + index: event.index, + } + } + } -impl From for pb::Event { - fn from(event: Event) -> Self { - Self { - r#type: event.kind, - attributes: event.attributes.into_iter().map(Into::into).collect(), + impl TryFrom for EventAttribute { + type Error = crate::Error; + + fn try_from(event: pb::EventAttribute) -> Result { + // We insist that keys and values are strings, like tm 0.35 did. + Ok(Self { + key: event.key, + value: event.value, + index: event.index, + }) } } -} -impl TryFrom for Event { - type Error = crate::Error; - - fn try_from(event: pb::Event) -> Result { - Ok(Self { - kind: event.r#type, - attributes: event - .attributes - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - }) + impl Protobuf for EventAttribute {} + + impl From for pb::Event { + fn from(event: Event) -> Self { + Self { + r#type: event.kind, + attributes: event.attributes.into_iter().map(Into::into).collect(), + } + } } -} -impl Protobuf for Event {} + impl TryFrom for Event { + type Error = crate::Error; + + fn try_from(event: pb::Event) -> Result { + Ok(Self { + kind: event.r#type, + attributes: event + .attributes + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } + } + + impl Protobuf for Event {} +} diff --git a/tendermint/src/abci/request.rs b/tendermint/src/abci/request.rs index 990b567d9..40f9bbdcf 100644 --- a/tendermint/src/abci/request.rs +++ b/tendermint/src/abci/request.rs @@ -1,8 +1,5 @@ //! ABCI requests and request data. //! -//! The [`Request`] enum records all possible ABCI requests. Requests that -//! contain data are modeled as a separate struct, to avoid duplication of field -//! definitions. // IMPORTANT NOTE ON DOCUMENTATION: // @@ -18,26 +15,25 @@ // This is also why certain submodules have #[allow(unused)] imports to bring // items into scope for doc links, rather than changing the doc links -- it // allows the doc comments to be copied without editing. -use core::convert::{TryFrom, TryInto}; // bring into scope for doc links #[allow(unused)] use super::types::Snapshot; -use super::MethodKind; -use crate::{prelude::*, Error}; -mod apply_snapshot_chunk; -mod begin_block; -mod check_tx; -mod deliver_tx; -mod echo; -mod end_block; -mod info; -mod init_chain; -mod load_snapshot_chunk; -mod offer_snapshot; -mod query; -mod set_option; +pub(super) mod apply_snapshot_chunk; +pub(super) mod begin_block; +pub(super) mod check_tx; +pub(super) mod deliver_tx; +pub(super) mod echo; +pub(super) mod end_block; +pub(super) mod info; +pub(super) mod init_chain; +pub(super) mod load_snapshot_chunk; +pub(super) mod offer_snapshot; +pub(super) mod prepare_proposal; +pub(super) mod process_proposal; +pub(super) mod query; +pub(super) mod set_option; pub use apply_snapshot_chunk::ApplySnapshotChunk; pub use begin_block::BeginBlock; @@ -49,75 +45,21 @@ pub use info::Info; pub use init_chain::InitChain; pub use load_snapshot_chunk::LoadSnapshotChunk; pub use offer_snapshot::OfferSnapshot; +pub use prepare_proposal::PrepareProposal; +pub use process_proposal::ProcessProposal; pub use query::Query; pub use set_option::SetOption; -/// All possible ABCI requests. -#[allow(clippy::large_enum_variant)] -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum Request { - #[doc = include_str!("doc/request-echo.md")] - Echo(Echo), - #[doc = include_str!("doc/request-flush.md")] - Flush, - #[doc = include_str!("doc/request-info.md")] - Info(Info), - #[doc = include_str!("doc/request-setoption.md")] - SetOption(SetOption), - #[doc = include_str!("doc/request-initchain.md")] - InitChain(InitChain), - #[doc = include_str!("doc/request-query.md")] - Query(Query), - #[doc = include_str!("doc/request-beginblock.md")] - BeginBlock(BeginBlock), - #[doc = include_str!("doc/request-checktx.md")] - CheckTx(CheckTx), - #[doc = include_str!("doc/request-delivertx.md")] - DeliverTx(DeliverTx), - #[doc = include_str!("doc/request-endblock.md")] - EndBlock(EndBlock), - #[doc = include_str!("doc/request-commit.md")] - Commit, - #[doc = include_str!("doc/request-listsnapshots.md")] - ListSnapshots, - #[doc = include_str!("doc/request-offersnapshot.md")] - OfferSnapshot(OfferSnapshot), - #[doc = include_str!("doc/request-loadsnapshotchunk.md")] - LoadSnapshotChunk(LoadSnapshotChunk), - #[doc = include_str!("doc/request-applysnapshotchunk.md")] - ApplySnapshotChunk(ApplySnapshotChunk), -} - -impl Request { - /// Get the method kind for this request. - pub fn kind(&self) -> MethodKind { - use Request::*; - match self { - Flush => MethodKind::Flush, - InitChain(_) => MethodKind::Consensus, - BeginBlock(_) => MethodKind::Consensus, - DeliverTx(_) => MethodKind::Consensus, - EndBlock(_) => MethodKind::Consensus, - Commit => MethodKind::Consensus, - CheckTx(_) => MethodKind::Mempool, - ListSnapshots => MethodKind::Snapshot, - OfferSnapshot(_) => MethodKind::Snapshot, - LoadSnapshotChunk(_) => MethodKind::Snapshot, - ApplySnapshotChunk(_) => MethodKind::Snapshot, - Info(_) => MethodKind::Info, - Query(_) => MethodKind::Info, - Echo(_) => MethodKind::Info, - SetOption(_) => MethodKind::Info, - } - } -} - /// The consensus category of ABCI requests. #[allow(clippy::large_enum_variant)] #[derive(Clone, PartialEq, Eq, Debug)] pub enum ConsensusRequest { #[doc = include_str!("doc/request-initchain.md")] InitChain(InitChain), + #[doc = include_str!("doc/request-prepareproposal.md")] + PrepareProposal(PrepareProposal), + #[doc = include_str!("doc/request-processproposal.md")] + ProcessProposal(ProcessProposal), #[doc = include_str!("doc/request-beginblock.md")] BeginBlock(BeginBlock), #[doc = include_str!("doc/request-delivertx.md")] @@ -128,32 +70,6 @@ pub enum ConsensusRequest { Commit, } -impl From for Request { - fn from(req: ConsensusRequest) -> Self { - match req { - ConsensusRequest::InitChain(x) => Self::InitChain(x), - ConsensusRequest::BeginBlock(x) => Self::BeginBlock(x), - ConsensusRequest::DeliverTx(x) => Self::DeliverTx(x), - ConsensusRequest::EndBlock(x) => Self::EndBlock(x), - ConsensusRequest::Commit => Self::Commit, - } - } -} - -impl TryFrom for ConsensusRequest { - type Error = Error; - fn try_from(req: Request) -> Result { - match req { - Request::InitChain(x) => Ok(Self::InitChain(x)), - Request::BeginBlock(x) => Ok(Self::BeginBlock(x)), - Request::DeliverTx(x) => Ok(Self::DeliverTx(x)), - Request::EndBlock(x) => Ok(Self::EndBlock(x)), - Request::Commit => Ok(Self::Commit), - _ => Err(Error::invalid_abci_request_type()), - } - } -} - /// The mempool category of ABCI requests. #[derive(Clone, PartialEq, Eq, Debug)] pub enum MempoolRequest { @@ -161,24 +77,6 @@ pub enum MempoolRequest { CheckTx(CheckTx), } -impl From for Request { - fn from(req: MempoolRequest) -> Self { - match req { - MempoolRequest::CheckTx(x) => Self::CheckTx(x), - } - } -} - -impl TryFrom for MempoolRequest { - type Error = Error; - fn try_from(req: Request) -> Result { - match req { - Request::CheckTx(x) => Ok(Self::CheckTx(x)), - _ => Err(Error::invalid_abci_request_type()), - } - } -} - /// The info category of ABCI requests. #[derive(Clone, PartialEq, Eq, Debug)] pub enum InfoRequest { @@ -192,30 +90,6 @@ pub enum InfoRequest { SetOption(SetOption), } -impl From for Request { - fn from(req: InfoRequest) -> Self { - match req { - InfoRequest::Info(x) => Self::Info(x), - InfoRequest::Query(x) => Self::Query(x), - InfoRequest::Echo(x) => Self::Echo(x), - InfoRequest::SetOption(x) => Self::SetOption(x), - } - } -} - -impl TryFrom for InfoRequest { - type Error = Error; - fn try_from(req: Request) -> Result { - match req { - Request::Info(x) => Ok(Self::Info(x)), - Request::Query(x) => Ok(Self::Query(x)), - Request::Echo(x) => Ok(Self::Echo(x)), - Request::SetOption(x) => Ok(Self::SetOption(x)), - _ => Err(Error::invalid_abci_request_type()), - } - } -} - /// The snapshot category of ABCI requests. #[derive(Clone, PartialEq, Eq, Debug)] pub enum SnapshotRequest { @@ -228,85 +102,3 @@ pub enum SnapshotRequest { #[doc = include_str!("doc/request-applysnapshotchunk.md")] ApplySnapshotChunk(ApplySnapshotChunk), } - -impl From for Request { - fn from(req: SnapshotRequest) -> Self { - match req { - SnapshotRequest::ListSnapshots => Self::ListSnapshots, - SnapshotRequest::OfferSnapshot(x) => Self::OfferSnapshot(x), - SnapshotRequest::LoadSnapshotChunk(x) => Self::LoadSnapshotChunk(x), - SnapshotRequest::ApplySnapshotChunk(x) => Self::ApplySnapshotChunk(x), - } - } -} - -impl TryFrom for SnapshotRequest { - type Error = Error; - fn try_from(req: Request) -> Result { - match req { - Request::ListSnapshots => Ok(Self::ListSnapshots), - Request::OfferSnapshot(x) => Ok(Self::OfferSnapshot(x)), - Request::LoadSnapshotChunk(x) => Ok(Self::LoadSnapshotChunk(x)), - Request::ApplySnapshotChunk(x) => Ok(Self::ApplySnapshotChunk(x)), - _ => Err(Error::invalid_abci_request_type()), - } - } -} - -// ============================================================================= -// Protobuf conversions -// ============================================================================= - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::Request { - fn from(request: Request) -> pb::Request { - use pb::request::Value; - let value = match request { - Request::Echo(x) => Some(Value::Echo(x.into())), - Request::Flush => Some(Value::Flush(Default::default())), - Request::Info(x) => Some(Value::Info(x.into())), - Request::SetOption(x) => Some(Value::SetOption(x.into())), - Request::InitChain(x) => Some(Value::InitChain(x.into())), - Request::Query(x) => Some(Value::Query(x.into())), - Request::BeginBlock(x) => Some(Value::BeginBlock(x.into())), - Request::CheckTx(x) => Some(Value::CheckTx(x.into())), - Request::DeliverTx(x) => Some(Value::DeliverTx(x.into())), - Request::EndBlock(x) => Some(Value::EndBlock(x.into())), - Request::Commit => Some(Value::Commit(Default::default())), - Request::ListSnapshots => Some(Value::ListSnapshots(Default::default())), - Request::OfferSnapshot(x) => Some(Value::OfferSnapshot(x.into())), - Request::LoadSnapshotChunk(x) => Some(Value::LoadSnapshotChunk(x.into())), - Request::ApplySnapshotChunk(x) => Some(Value::ApplySnapshotChunk(x.into())), - }; - pb::Request { value } - } -} - -impl TryFrom for Request { - type Error = Error; - - fn try_from(request: pb::Request) -> Result { - use pb::request::Value; - match request.value { - Some(Value::Echo(x)) => Ok(Request::Echo(x.try_into()?)), - Some(Value::Flush(pb::RequestFlush {})) => Ok(Request::Flush), - Some(Value::Info(x)) => Ok(Request::Info(x.try_into()?)), - Some(Value::SetOption(x)) => Ok(Request::SetOption(x.try_into()?)), - Some(Value::InitChain(x)) => Ok(Request::InitChain(x.try_into()?)), - Some(Value::Query(x)) => Ok(Request::Query(x.try_into()?)), - Some(Value::BeginBlock(x)) => Ok(Request::BeginBlock(x.try_into()?)), - Some(Value::CheckTx(x)) => Ok(Request::CheckTx(x.try_into()?)), - Some(Value::DeliverTx(x)) => Ok(Request::DeliverTx(x.try_into()?)), - Some(Value::EndBlock(x)) => Ok(Request::EndBlock(x.try_into()?)), - Some(Value::Commit(pb::RequestCommit {})) => Ok(Request::Commit), - Some(Value::ListSnapshots(pb::RequestListSnapshots {})) => Ok(Request::ListSnapshots), - Some(Value::OfferSnapshot(x)) => Ok(Request::OfferSnapshot(x.try_into()?)), - Some(Value::LoadSnapshotChunk(x)) => Ok(Request::LoadSnapshotChunk(x.try_into()?)), - Some(Value::ApplySnapshotChunk(x)) => Ok(Request::ApplySnapshotChunk(x.try_into()?)), - None => Err(crate::Error::missing_data()), - } - } -} - -impl Protobuf for Request {} diff --git a/tendermint/src/abci/request/apply_snapshot_chunk.rs b/tendermint/src/abci/request/apply_snapshot_chunk.rs index f893cbb47..d11f1b3c6 100644 --- a/tendermint/src/abci/request/apply_snapshot_chunk.rs +++ b/tendermint/src/abci/request/apply_snapshot_chunk.rs @@ -40,30 +40,30 @@ pub struct ApplySnapshotChunk { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; +tendermint_pb_modules! { + use super::ApplySnapshotChunk; -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::RequestApplySnapshotChunk { - fn from(apply_snapshot_chunk: ApplySnapshotChunk) -> Self { - Self { - index: apply_snapshot_chunk.index, - chunk: apply_snapshot_chunk.chunk, - sender: apply_snapshot_chunk.sender, + impl From for pb::abci::RequestApplySnapshotChunk { + fn from(apply_snapshot_chunk: ApplySnapshotChunk) -> Self { + Self { + index: apply_snapshot_chunk.index, + chunk: apply_snapshot_chunk.chunk, + sender: apply_snapshot_chunk.sender, + } } } -} -impl TryFrom for ApplySnapshotChunk { - type Error = crate::Error; + impl TryFrom for ApplySnapshotChunk { + type Error = crate::Error; - fn try_from(apply_snapshot_chunk: pb::RequestApplySnapshotChunk) -> Result { - Ok(Self { - index: apply_snapshot_chunk.index, - chunk: apply_snapshot_chunk.chunk, - sender: apply_snapshot_chunk.sender, - }) + fn try_from(apply_snapshot_chunk: pb::abci::RequestApplySnapshotChunk) -> Result { + Ok(Self { + index: apply_snapshot_chunk.index, + chunk: apply_snapshot_chunk.chunk, + sender: apply_snapshot_chunk.sender, + }) + } } -} -impl Protobuf for ApplySnapshotChunk {} + impl Protobuf for ApplySnapshotChunk {} +} diff --git a/tendermint/src/abci/request/begin_block.rs b/tendermint/src/abci/request/begin_block.rs index e7da9be76..9174d77b3 100644 --- a/tendermint/src/abci/request/begin_block.rs +++ b/tendermint/src/abci/request/begin_block.rs @@ -1,8 +1,12 @@ -use super::super::types::{Evidence, LastCommitInfo}; // bring into scope for doc links #[allow(unused)] use super::DeliverTx; -use crate::{block, prelude::*, Error, Hash}; +use crate::{ + abci::types::{CommitInfo, Misbehavior}, + block, + prelude::*, + Hash, +}; #[doc = include_str!("../doc/request-beginblock.md")] #[derive(Clone, PartialEq, Eq, Debug)] @@ -17,55 +21,56 @@ pub struct BeginBlock { /// /// This includes the round, the list of validators, and which validators /// signed the last block. - pub last_commit_info: LastCommitInfo, + pub last_commit_info: CommitInfo, /// Evidence of validator misbehavior. - pub byzantine_validators: Vec, + pub byzantine_validators: Vec, } // ============================================================================= // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; +tendermint_pb_modules! { + use super::BeginBlock; + use crate::Error; -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::RequestBeginBlock { - fn from(begin_block: BeginBlock) -> Self { - Self { - hash: begin_block.hash.into(), - header: Some(begin_block.header.into()), - last_commit_info: Some(begin_block.last_commit_info.into()), - byzantine_validators: begin_block - .byzantine_validators - .into_iter() - .map(Into::into) - .collect(), + impl From for pb::abci::RequestBeginBlock { + fn from(begin_block: BeginBlock) -> Self { + Self { + hash: begin_block.hash.into(), + header: Some(begin_block.header.into()), + last_commit_info: Some(begin_block.last_commit_info.into()), + byzantine_validators: begin_block + .byzantine_validators + .into_iter() + .map(Into::into) + .collect(), + } } } -} -impl TryFrom for BeginBlock { - type Error = Error; + impl TryFrom for BeginBlock { + type Error = Error; - fn try_from(begin_block: pb::RequestBeginBlock) -> Result { - Ok(Self { - hash: begin_block.hash.try_into()?, - header: begin_block - .header - .ok_or_else(Error::missing_header)? - .try_into()?, - last_commit_info: begin_block - .last_commit_info - .ok_or_else(Error::missing_last_commit_info)? - .try_into()?, - byzantine_validators: begin_block - .byzantine_validators - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - }) + fn try_from(begin_block: pb::abci::RequestBeginBlock) -> Result { + Ok(Self { + hash: begin_block.hash.try_into()?, + header: begin_block + .header + .ok_or_else(Error::missing_header)? + .try_into()?, + last_commit_info: begin_block + .last_commit_info + .ok_or_else(Error::missing_last_commit_info)? + .try_into()?, + byzantine_validators: begin_block + .byzantine_validators + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } } -} -impl Protobuf for BeginBlock {} + impl Protobuf for BeginBlock {} +} diff --git a/tendermint/src/abci/request/check_tx.rs b/tendermint/src/abci/request/check_tx.rs index 0fbf8f10f..8afbc5af7 100644 --- a/tendermint/src/abci/request/check_tx.rs +++ b/tendermint/src/abci/request/check_tx.rs @@ -39,33 +39,33 @@ impl Default for CheckTxKind { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; +tendermint_pb_modules! { + use super::{CheckTx, CheckTxKind}; -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::RequestCheckTx { - fn from(check_tx: CheckTx) -> Self { - Self { - tx: check_tx.tx, - r#type: check_tx.kind as i32, + impl From for pb::abci::RequestCheckTx { + fn from(check_tx: CheckTx) -> Self { + Self { + tx: check_tx.tx, + r#type: check_tx.kind as i32, + } } } -} -impl TryFrom for CheckTx { - type Error = crate::Error; + impl TryFrom for CheckTx { + type Error = crate::Error; - fn try_from(check_tx: pb::RequestCheckTx) -> Result { - let kind = match check_tx.r#type { - 0 => CheckTxKind::New, - 1 => CheckTxKind::Recheck, - _ => return Err(crate::Error::unsupported_check_tx_type()), - }; - Ok(Self { - tx: check_tx.tx, - kind, - }) + fn try_from(check_tx: pb::abci::RequestCheckTx) -> Result { + let kind = match check_tx.r#type { + 0 => CheckTxKind::New, + 1 => CheckTxKind::Recheck, + _ => return Err(crate::Error::unsupported_check_tx_type()), + }; + Ok(Self { + tx: check_tx.tx, + kind, + }) + } } -} -impl Protobuf for CheckTx {} + impl Protobuf for CheckTx {} +} diff --git a/tendermint/src/abci/request/deliver_tx.rs b/tendermint/src/abci/request/deliver_tx.rs index 4c9bc6d50..83fc11a14 100644 --- a/tendermint/src/abci/request/deliver_tx.rs +++ b/tendermint/src/abci/request/deliver_tx.rs @@ -13,22 +13,22 @@ pub struct DeliverTx { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; +tendermint_pb_modules! { + use super::DeliverTx; -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::RequestDeliverTx { - fn from(deliver_tx: DeliverTx) -> Self { - Self { tx: deliver_tx.tx } + impl From for pb::abci::RequestDeliverTx { + fn from(deliver_tx: DeliverTx) -> Self { + Self { tx: deliver_tx.tx } + } } -} -impl TryFrom for DeliverTx { - type Error = crate::Error; + impl TryFrom for DeliverTx { + type Error = crate::Error; - fn try_from(deliver_tx: pb::RequestDeliverTx) -> Result { - Ok(Self { tx: deliver_tx.tx }) + fn try_from(deliver_tx: pb::abci::RequestDeliverTx) -> Result { + Ok(Self { tx: deliver_tx.tx }) + } } -} -impl Protobuf for DeliverTx {} + impl Protobuf for DeliverTx {} +} diff --git a/tendermint/src/abci/request/echo.rs b/tendermint/src/abci/request/echo.rs index 3ae62456e..d930c7691 100644 --- a/tendermint/src/abci/request/echo.rs +++ b/tendermint/src/abci/request/echo.rs @@ -11,26 +11,26 @@ pub struct Echo { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::RequestEcho { - fn from(echo: Echo) -> Self { - Self { - message: echo.message, +tendermint_pb_modules! { + use super::Echo; + + impl From for pb::abci::RequestEcho { + fn from(echo: Echo) -> Self { + Self { + message: echo.message, + } } } -} -impl TryFrom for Echo { - type Error = crate::Error; + impl TryFrom for Echo { + type Error = crate::Error; - fn try_from(echo: pb::RequestEcho) -> Result { - Ok(Self { - message: echo.message, - }) + fn try_from(echo: pb::abci::RequestEcho) -> Result { + Ok(Self { + message: echo.message, + }) + } } -} -impl Protobuf for Echo {} + impl Protobuf for Echo {} +} diff --git a/tendermint/src/abci/request/end_block.rs b/tendermint/src/abci/request/end_block.rs index 7095ea39f..c3b05b8b8 100644 --- a/tendermint/src/abci/request/end_block.rs +++ b/tendermint/src/abci/request/end_block.rs @@ -11,26 +11,26 @@ pub struct EndBlock { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::RequestEndBlock { - fn from(end_block: EndBlock) -> Self { - Self { - height: end_block.height, +tendermint_pb_modules! { + use super::EndBlock; + + impl From for pb::abci::RequestEndBlock { + fn from(end_block: EndBlock) -> Self { + Self { + height: end_block.height, + } } } -} -impl TryFrom for EndBlock { - type Error = crate::Error; + impl TryFrom for EndBlock { + type Error = crate::Error; - fn try_from(end_block: pb::RequestEndBlock) -> Result { - Ok(Self { - height: end_block.height, - }) + fn try_from(end_block: pb::abci::RequestEndBlock) -> Result { + Ok(Self { + height: end_block.height, + }) + } } -} -impl Protobuf for EndBlock {} + impl Protobuf for EndBlock {} +} diff --git a/tendermint/src/abci/request/info.rs b/tendermint/src/abci/request/info.rs index 1a2c900d8..f9be161b6 100644 --- a/tendermint/src/abci/request/info.rs +++ b/tendermint/src/abci/request/info.rs @@ -9,36 +9,73 @@ pub struct Info { pub block_version: u64, /// The Tendermint p2p protocol version. pub p2p_version: u64, + /// The ABCI protocol version. + pub abci_version: String, } // ============================================================================= // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; +mod v0_34 { + use super::Info; + use tendermint_proto::v0_34::abci as pb; + use tendermint_proto::Protobuf; -use tendermint_proto::{abci as pb, Protobuf}; + impl From for pb::RequestInfo { + fn from(info: Info) -> Self { + Self { + version: info.version, + block_version: info.block_version, + p2p_version: info.p2p_version, + } + } + } + + impl TryFrom for Info { + type Error = crate::Error; -impl From for pb::RequestInfo { - fn from(info: Info) -> Self { - Self { - version: info.version, - block_version: info.block_version, - p2p_version: info.p2p_version, + fn try_from(info: pb::RequestInfo) -> Result { + Ok(Self { + version: info.version, + block_version: info.block_version, + p2p_version: info.p2p_version, + abci_version: Default::default(), + }) } } + + impl Protobuf for Info {} } -impl TryFrom for Info { - type Error = crate::Error; +mod v0_37 { + use super::Info; + use tendermint_proto::v0_37::abci as pb; + use tendermint_proto::Protobuf; - fn try_from(info: pb::RequestInfo) -> Result { - Ok(Self { - version: info.version, - block_version: info.block_version, - p2p_version: info.p2p_version, - }) + impl From for pb::RequestInfo { + fn from(info: Info) -> Self { + Self { + version: info.version, + block_version: info.block_version, + p2p_version: info.p2p_version, + abci_version: info.abci_version, + } + } } -} -impl Protobuf for Info {} + impl TryFrom for Info { + type Error = crate::Error; + + fn try_from(info: pb::RequestInfo) -> Result { + Ok(Self { + version: info.version, + block_version: info.block_version, + p2p_version: info.p2p_version, + abci_version: info.abci_version, + }) + } + } + + impl Protobuf for Info {} +} diff --git a/tendermint/src/abci/request/init_chain.rs b/tendermint/src/abci/request/init_chain.rs index 31a803f3f..6c5d01836 100644 --- a/tendermint/src/abci/request/init_chain.rs +++ b/tendermint/src/abci/request/init_chain.rs @@ -25,48 +25,47 @@ pub struct InitChain { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; +tendermint_pb_modules! { + use super::InitChain; + use crate::Error; -use tendermint_proto::{abci as pb, Protobuf}; - -use crate::Error; - -impl From for pb::RequestInitChain { - fn from(init_chain: InitChain) -> Self { - Self { - time: Some(init_chain.time.into()), - chain_id: init_chain.chain_id, - consensus_params: Some(init_chain.consensus_params.into()), - validators: init_chain.validators.into_iter().map(Into::into).collect(), - app_state_bytes: init_chain.app_state_bytes, - initial_height: init_chain.initial_height.into(), + impl From for pb::abci::RequestInitChain { + fn from(init_chain: InitChain) -> Self { + Self { + time: Some(init_chain.time.into()), + chain_id: init_chain.chain_id, + consensus_params: Some(init_chain.consensus_params.into()), + validators: init_chain.validators.into_iter().map(Into::into).collect(), + app_state_bytes: init_chain.app_state_bytes, + initial_height: init_chain.initial_height.into(), + } } } -} -impl TryFrom for InitChain { - type Error = Error; + impl TryFrom for InitChain { + type Error = Error; - fn try_from(init_chain: pb::RequestInitChain) -> Result { - Ok(Self { - time: init_chain - .time - .ok_or_else(Error::missing_genesis_time)? - .try_into()?, - chain_id: init_chain.chain_id, - consensus_params: init_chain - .consensus_params - .ok_or_else(Error::missing_consensus_params)? - .try_into()?, - validators: init_chain - .validators - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - app_state_bytes: init_chain.app_state_bytes, - initial_height: init_chain.initial_height.try_into()?, - }) + fn try_from(init_chain: pb::abci::RequestInitChain) -> Result { + Ok(Self { + time: init_chain + .time + .ok_or_else(Error::missing_genesis_time)? + .try_into()?, + chain_id: init_chain.chain_id, + consensus_params: init_chain + .consensus_params + .ok_or_else(Error::missing_consensus_params)? + .try_into()?, + validators: init_chain + .validators + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + app_state_bytes: init_chain.app_state_bytes, + initial_height: init_chain.initial_height.try_into()?, + }) + } } -} -impl Protobuf for InitChain {} + impl Protobuf for InitChain {} +} diff --git a/tendermint/src/abci/request/load_snapshot_chunk.rs b/tendermint/src/abci/request/load_snapshot_chunk.rs index 4c56ed6e3..1639c27f9 100644 --- a/tendermint/src/abci/request/load_snapshot_chunk.rs +++ b/tendermint/src/abci/request/load_snapshot_chunk.rs @@ -15,30 +15,30 @@ pub struct LoadSnapshotChunk { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::RequestLoadSnapshotChunk { - fn from(load_snapshot_chunk: LoadSnapshotChunk) -> Self { - Self { - height: load_snapshot_chunk.height.into(), - format: load_snapshot_chunk.format, - chunk: load_snapshot_chunk.chunk, +tendermint_pb_modules! { + use super::LoadSnapshotChunk; + + impl From for pb::abci::RequestLoadSnapshotChunk { + fn from(load_snapshot_chunk: LoadSnapshotChunk) -> Self { + Self { + height: load_snapshot_chunk.height.into(), + format: load_snapshot_chunk.format, + chunk: load_snapshot_chunk.chunk, + } } } -} -impl TryFrom for LoadSnapshotChunk { - type Error = crate::Error; + impl TryFrom for LoadSnapshotChunk { + type Error = crate::Error; - fn try_from(load_snapshot_chunk: pb::RequestLoadSnapshotChunk) -> Result { - Ok(Self { - height: load_snapshot_chunk.height.try_into()?, - format: load_snapshot_chunk.format, - chunk: load_snapshot_chunk.chunk, - }) + fn try_from(load_snapshot_chunk: pb::abci::RequestLoadSnapshotChunk) -> Result { + Ok(Self { + height: load_snapshot_chunk.height.try_into()?, + format: load_snapshot_chunk.format, + chunk: load_snapshot_chunk.chunk, + }) + } } -} -impl Protobuf for LoadSnapshotChunk {} + impl Protobuf for LoadSnapshotChunk {} +} diff --git a/tendermint/src/abci/request/offer_snapshot.rs b/tendermint/src/abci/request/offer_snapshot.rs index c641c8ad2..af50c0c75 100644 --- a/tendermint/src/abci/request/offer_snapshot.rs +++ b/tendermint/src/abci/request/offer_snapshot.rs @@ -17,31 +17,31 @@ pub struct OfferSnapshot { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::RequestOfferSnapshot { - fn from(offer_snapshot: OfferSnapshot) -> Self { - Self { - snapshot: Some(offer_snapshot.snapshot.into()), - app_hash: offer_snapshot.app_hash.into(), +tendermint_pb_modules! { + use super::OfferSnapshot; + + impl From for pb::abci::RequestOfferSnapshot { + fn from(offer_snapshot: OfferSnapshot) -> Self { + Self { + snapshot: Some(offer_snapshot.snapshot.into()), + app_hash: offer_snapshot.app_hash.into(), + } } } -} - -impl TryFrom for OfferSnapshot { - type Error = crate::Error; - fn try_from(offer_snapshot: pb::RequestOfferSnapshot) -> Result { - Ok(Self { - snapshot: offer_snapshot - .snapshot - .ok_or_else(crate::Error::missing_data)? - .try_into()?, - app_hash: offer_snapshot.app_hash.try_into()?, - }) + impl TryFrom for OfferSnapshot { + type Error = crate::Error; + + fn try_from(offer_snapshot: pb::abci::RequestOfferSnapshot) -> Result { + Ok(Self { + snapshot: offer_snapshot + .snapshot + .ok_or_else(crate::Error::missing_data)? + .try_into()?, + app_hash: offer_snapshot.app_hash.try_into()?, + }) + } } -} -impl Protobuf for OfferSnapshot {} + impl Protobuf for OfferSnapshot {} +} diff --git a/tendermint/src/abci/request/prepare_proposal.rs b/tendermint/src/abci/request/prepare_proposal.rs new file mode 100644 index 000000000..a95dc691e --- /dev/null +++ b/tendermint/src/abci/request/prepare_proposal.rs @@ -0,0 +1,78 @@ +use crate::prelude::*; +use crate::{ + abci::types::{CommitInfo, Misbehavior}, + account, block, Error, Hash, Time, +}; + +use bytes::Bytes; + +#[doc = include_str!("../doc/request-prepareproposal.md")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct PrepareProposal { + /// the modified transactions cannot exceed this size. + pub max_tx_bytes: i64, + /// txs is an array of transactions that will be included in a block, + /// sent to the app for possible modifications. + pub txs: Vec, + pub local_last_commit: Option, + pub misbehavior: Vec, + pub height: block::Height, + pub time: Time, + pub next_validators_hash: Hash, + /// address of the public key of the validator proposing the block. + pub proposer_address: account::Id, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +// The PrepareProposal request has been added in 0.37. + +use tendermint_proto::v0_37::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestPrepareProposal { + fn from(value: PrepareProposal) -> Self { + Self { + max_tx_bytes: value.max_tx_bytes, + txs: value.txs, + local_last_commit: value.local_last_commit.map(Into::into), + misbehavior: value.misbehavior.into_iter().map(Into::into).collect(), + height: value.height.into(), + time: Some(value.time.into()), + next_validators_hash: value.next_validators_hash.into(), + proposer_address: value.proposer_address.into(), + } + } +} + +impl TryFrom for PrepareProposal { + type Error = Error; + + fn try_from(message: pb::RequestPrepareProposal) -> Result { + let req = Self { + max_tx_bytes: message.max_tx_bytes, + txs: message.txs, + local_last_commit: message + .local_last_commit + .map(TryInto::try_into) + .transpose()?, + misbehavior: message + .misbehavior + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?, + height: message.height.try_into()?, + time: message + .time + .ok_or_else(Error::missing_timestamp)? + .try_into()?, + next_validators_hash: message.next_validators_hash.try_into()?, + proposer_address: message.proposer_address.try_into()?, + }; + Ok(req) + } +} + +impl Protobuf for PrepareProposal {} diff --git a/tendermint/src/abci/request/process_proposal.rs b/tendermint/src/abci/request/process_proposal.rs new file mode 100644 index 000000000..bb3020048 --- /dev/null +++ b/tendermint/src/abci/request/process_proposal.rs @@ -0,0 +1,77 @@ +use crate::prelude::*; +use crate::{ + abci::types::{CommitInfo, Misbehavior}, + account, block, Error, Hash, Time, +}; + +use bytes::Bytes; + +#[doc = include_str!("../doc/request-processproposal.md")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ProcessProposal { + /// txs is an array of transactions that will be included in a block, + /// sent to the app for possible modifications. + pub txs: Vec, + pub proposed_last_commit: Option, + pub misbehavior: Vec, + pub hash: Hash, + pub height: block::Height, + pub time: Time, + pub next_validators_hash: Hash, + /// address of the public key of the validator proposing the block. + pub proposer_address: account::Id, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +// The ProcessProposal request has been added in 0.37. + +use tendermint_proto::v0_37::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestProcessProposal { + fn from(value: ProcessProposal) -> Self { + Self { + txs: value.txs, + proposed_last_commit: value.proposed_last_commit.map(Into::into), + misbehavior: value.misbehavior.into_iter().map(Into::into).collect(), + hash: value.hash.into(), + height: value.height.into(), + time: Some(value.time.into()), + next_validators_hash: value.next_validators_hash.into(), + proposer_address: value.proposer_address.into(), + } + } +} + +impl TryFrom for ProcessProposal { + type Error = Error; + + fn try_from(message: pb::RequestProcessProposal) -> Result { + let req = Self { + txs: message.txs, + proposed_last_commit: message + .proposed_last_commit + .map(TryInto::try_into) + .transpose()?, + misbehavior: message + .misbehavior + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?, + hash: message.hash.try_into()?, + height: message.height.try_into()?, + time: message + .time + .ok_or_else(Error::missing_timestamp)? + .try_into()?, + next_validators_hash: message.next_validators_hash.try_into()?, + proposer_address: message.proposer_address.try_into()?, + }; + Ok(req) + } +} + +impl Protobuf for ProcessProposal {} diff --git a/tendermint/src/abci/request/query.rs b/tendermint/src/abci/request/query.rs index 07dade853..260a4a120 100644 --- a/tendermint/src/abci/request/query.rs +++ b/tendermint/src/abci/request/query.rs @@ -32,32 +32,32 @@ pub struct Query { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::RequestQuery { - fn from(query: Query) -> Self { - Self { - data: query.data, - path: query.path, - height: query.height.into(), - prove: query.prove, +tendermint_pb_modules! { + use super::Query; + + impl From for pb::abci::RequestQuery { + fn from(query: Query) -> Self { + Self { + data: query.data, + path: query.path, + height: query.height.into(), + prove: query.prove, + } } } -} -impl TryFrom for Query { - type Error = crate::Error; + impl TryFrom for Query { + type Error = crate::Error; - fn try_from(query: pb::RequestQuery) -> Result { - Ok(Self { - data: query.data, - path: query.path, - height: query.height.try_into()?, - prove: query.prove, - }) + fn try_from(query: pb::abci::RequestQuery) -> Result { + Ok(Self { + data: query.data, + path: query.path, + height: query.height.try_into()?, + prove: query.prove, + }) + } } -} -impl Protobuf for Query {} + impl Protobuf for Query {} +} diff --git a/tendermint/src/abci/request/set_option.rs b/tendermint/src/abci/request/set_option.rs index ffb4dd9bb..3f2f5397c 100644 --- a/tendermint/src/abci/request/set_option.rs +++ b/tendermint/src/abci/request/set_option.rs @@ -11,9 +11,10 @@ pub struct SetOption { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; +// The SetOption request has been removed after 0.34. -use tendermint_proto::{abci as pb, Protobuf}; +use tendermint_proto::v0_34::abci as pb; +use tendermint_proto::Protobuf; impl From for pb::RequestSetOption { fn from(message: SetOption) -> Self { diff --git a/tendermint/src/abci/response.rs b/tendermint/src/abci/response.rs index 5b55a7116..725de9f7d 100644 --- a/tendermint/src/abci/response.rs +++ b/tendermint/src/abci/response.rs @@ -1,8 +1,4 @@ //! ABCI responses and response data. -//! -//! The [`Response`] enum records all possible ABCI responses. Responses that -//! contain data are modeled as a separate struct, to avoid duplication of field -//! definitions. // IMPORTANT NOTE ON DOCUMENTATION: // @@ -18,12 +14,11 @@ // This is also why certain submodules have #[allow(unused)] imports to bring // items into scope for doc links, rather than changing the doc links -- it // allows the doc comments to be copied without editing. -use core::convert::{TryFrom, TryInto}; // bring into scope for doc links #[allow(unused)] use super::types::Snapshot; -use crate::{prelude::*, Error}; +use crate::prelude::*; mod apply_snapshot_chunk; mod begin_block; @@ -38,6 +33,8 @@ mod init_chain; mod list_snapshots; mod load_snapshot_chunk; mod offer_snapshot; +mod prepare_proposal; +mod process_proposal; mod query; mod set_option; @@ -54,51 +51,20 @@ pub use init_chain::InitChain; pub use list_snapshots::ListSnapshots; pub use load_snapshot_chunk::LoadSnapshotChunk; pub use offer_snapshot::OfferSnapshot; +pub use prepare_proposal::PrepareProposal; +pub use process_proposal::ProcessProposal; pub use query::Query; pub use set_option::SetOption; -/// All possible ABCI responses. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum Response { - #[doc = include_str!("doc/response-exception.md")] - Exception(Exception), - #[doc = include_str!("doc/response-echo.md")] - Echo(Echo), - #[doc = include_str!("doc/response-flush.md")] - Flush, - #[doc = include_str!("doc/response-info.md")] - Info(Info), - #[doc = include_str!("doc/response-setoption.md")] - SetOption(SetOption), - #[doc = include_str!("doc/response-initchain.md")] - InitChain(InitChain), - #[doc = include_str!("doc/response-query.md")] - Query(Query), - #[doc = include_str!("doc/response-beginblock.md")] - BeginBlock(BeginBlock), - #[doc = include_str!("doc/response-checktx.md")] - CheckTx(CheckTx), - #[doc = include_str!("doc/response-delivertx.md")] - DeliverTx(DeliverTx), - #[doc = include_str!("doc/response-endblock.md")] - EndBlock(EndBlock), - #[doc = include_str!("doc/response-commit.md")] - Commit(Commit), - #[doc = include_str!("doc/response-listsnapshots.md")] - ListSnapshots(ListSnapshots), - #[doc = include_str!("doc/response-offersnapshot.md")] - OfferSnapshot(OfferSnapshot), - #[doc = include_str!("doc/response-loadsnapshotchunk.md")] - LoadSnapshotChunk(LoadSnapshotChunk), - #[doc = include_str!("doc/response-applysnapshotchunk.md")] - ApplySnapshotChunk(ApplySnapshotChunk), -} - /// The consensus category of ABCI responses. #[derive(Clone, PartialEq, Eq, Debug)] pub enum ConsensusResponse { #[doc = include_str!("doc/response-initchain.md")] InitChain(InitChain), + #[doc = include_str!("doc/response-prepareproposal.md")] + PrepareProposal(PrepareProposal), + #[doc = include_str!("doc/response-processproposal.md")] + ProcessProposal(ProcessProposal), #[doc = include_str!("doc/response-beginblock.md")] BeginBlock(BeginBlock), #[doc = include_str!("doc/response-delivertx.md")] @@ -109,32 +75,6 @@ pub enum ConsensusResponse { Commit(Commit), } -impl From for Response { - fn from(req: ConsensusResponse) -> Self { - match req { - ConsensusResponse::InitChain(x) => Self::InitChain(x), - ConsensusResponse::BeginBlock(x) => Self::BeginBlock(x), - ConsensusResponse::DeliverTx(x) => Self::DeliverTx(x), - ConsensusResponse::EndBlock(x) => Self::EndBlock(x), - ConsensusResponse::Commit(x) => Self::Commit(x), - } - } -} - -impl TryFrom for ConsensusResponse { - type Error = Error; - fn try_from(req: Response) -> Result { - match req { - Response::InitChain(x) => Ok(Self::InitChain(x)), - Response::BeginBlock(x) => Ok(Self::BeginBlock(x)), - Response::DeliverTx(x) => Ok(Self::DeliverTx(x)), - Response::EndBlock(x) => Ok(Self::EndBlock(x)), - Response::Commit(x) => Ok(Self::Commit(x)), - _ => Err(Error::invalid_abci_response_type()), - } - } -} - /// The mempool category of ABCI responses. #[derive(Clone, PartialEq, Eq, Debug)] pub enum MempoolResponse { @@ -142,24 +82,6 @@ pub enum MempoolResponse { CheckTx(CheckTx), } -impl From for Response { - fn from(req: MempoolResponse) -> Self { - match req { - MempoolResponse::CheckTx(x) => Self::CheckTx(x), - } - } -} - -impl TryFrom for MempoolResponse { - type Error = Error; - fn try_from(req: Response) -> Result { - match req { - Response::CheckTx(x) => Ok(Self::CheckTx(x)), - _ => Err(Error::invalid_abci_response_type()), - } - } -} - /// The info category of ABCI responses. #[derive(Clone, PartialEq, Eq, Debug)] pub enum InfoResponse { @@ -173,30 +95,6 @@ pub enum InfoResponse { SetOption(SetOption), } -impl From for Response { - fn from(req: InfoResponse) -> Self { - match req { - InfoResponse::Echo(x) => Self::Echo(x), - InfoResponse::Info(x) => Self::Info(x), - InfoResponse::Query(x) => Self::Query(x), - InfoResponse::SetOption(x) => Self::SetOption(x), - } - } -} - -impl TryFrom for InfoResponse { - type Error = Error; - fn try_from(req: Response) -> Result { - match req { - Response::Echo(x) => Ok(Self::Echo(x)), - Response::Info(x) => Ok(Self::Info(x)), - Response::Query(x) => Ok(Self::Query(x)), - Response::SetOption(x) => Ok(Self::SetOption(x)), - _ => Err(Error::invalid_abci_response_type()), - } - } -} - /// The snapshot category of ABCI responses. #[derive(Clone, PartialEq, Eq, Debug)] pub enum SnapshotResponse { @@ -209,87 +107,3 @@ pub enum SnapshotResponse { #[doc = include_str!("doc/response-applysnapshotchunk.md")] ApplySnapshotChunk(ApplySnapshotChunk), } - -impl From for Response { - fn from(req: SnapshotResponse) -> Self { - match req { - SnapshotResponse::ListSnapshots(x) => Self::ListSnapshots(x), - SnapshotResponse::OfferSnapshot(x) => Self::OfferSnapshot(x), - SnapshotResponse::LoadSnapshotChunk(x) => Self::LoadSnapshotChunk(x), - SnapshotResponse::ApplySnapshotChunk(x) => Self::ApplySnapshotChunk(x), - } - } -} - -impl TryFrom for SnapshotResponse { - type Error = Error; - fn try_from(req: Response) -> Result { - match req { - Response::ListSnapshots(x) => Ok(Self::ListSnapshots(x)), - Response::OfferSnapshot(x) => Ok(Self::OfferSnapshot(x)), - Response::LoadSnapshotChunk(x) => Ok(Self::LoadSnapshotChunk(x)), - Response::ApplySnapshotChunk(x) => Ok(Self::ApplySnapshotChunk(x)), - _ => Err(Error::invalid_abci_response_type()), - } - } -} - -// ============================================================================= -// Protobuf conversions -// ============================================================================= - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::Response { - fn from(response: Response) -> pb::Response { - use pb::response::Value; - let value = match response { - Response::Exception(x) => Some(Value::Exception(x.into())), - Response::Echo(x) => Some(Value::Echo(x.into())), - Response::Flush => Some(Value::Flush(Default::default())), - Response::Info(x) => Some(Value::Info(x.into())), - Response::SetOption(x) => Some(Value::SetOption(x.into())), - Response::InitChain(x) => Some(Value::InitChain(x.into())), - Response::Query(x) => Some(Value::Query(x.into())), - Response::BeginBlock(x) => Some(Value::BeginBlock(x.into())), - Response::CheckTx(x) => Some(Value::CheckTx(x.into())), - Response::DeliverTx(x) => Some(Value::DeliverTx(x.into())), - Response::EndBlock(x) => Some(Value::EndBlock(x.into())), - Response::Commit(x) => Some(Value::Commit(x.into())), - Response::ListSnapshots(x) => Some(Value::ListSnapshots(x.into())), - Response::OfferSnapshot(x) => Some(Value::OfferSnapshot(x.into())), - Response::LoadSnapshotChunk(x) => Some(Value::LoadSnapshotChunk(x.into())), - Response::ApplySnapshotChunk(x) => Some(Value::ApplySnapshotChunk(x.into())), - }; - pb::Response { value } - } -} - -impl TryFrom for Response { - type Error = Error; - - fn try_from(response: pb::Response) -> Result { - use pb::response::Value; - match response.value { - Some(Value::Exception(x)) => Ok(Response::Exception(x.try_into()?)), - Some(Value::Echo(x)) => Ok(Response::Echo(x.try_into()?)), - Some(Value::Flush(_)) => Ok(Response::Flush), - Some(Value::Info(x)) => Ok(Response::Info(x.try_into()?)), - Some(Value::SetOption(x)) => Ok(Response::SetOption(x.try_into()?)), - Some(Value::InitChain(x)) => Ok(Response::InitChain(x.try_into()?)), - Some(Value::Query(x)) => Ok(Response::Query(x.try_into()?)), - Some(Value::BeginBlock(x)) => Ok(Response::BeginBlock(x.try_into()?)), - Some(Value::CheckTx(x)) => Ok(Response::CheckTx(x.try_into()?)), - Some(Value::DeliverTx(x)) => Ok(Response::DeliverTx(x.try_into()?)), - Some(Value::EndBlock(x)) => Ok(Response::EndBlock(x.try_into()?)), - Some(Value::Commit(x)) => Ok(Response::Commit(x.try_into()?)), - Some(Value::ListSnapshots(x)) => Ok(Response::ListSnapshots(x.try_into()?)), - Some(Value::OfferSnapshot(x)) => Ok(Response::OfferSnapshot(x.try_into()?)), - Some(Value::LoadSnapshotChunk(x)) => Ok(Response::LoadSnapshotChunk(x.try_into()?)), - Some(Value::ApplySnapshotChunk(x)) => Ok(Response::ApplySnapshotChunk(x.try_into()?)), - None => Err(crate::Error::missing_data()), - } - } -} - -impl Protobuf for Response {} diff --git a/tendermint/src/abci/response/apply_snapshot_chunk.rs b/tendermint/src/abci/response/apply_snapshot_chunk.rs index b3502450a..94ff7586e 100644 --- a/tendermint/src/abci/response/apply_snapshot_chunk.rs +++ b/tendermint/src/abci/response/apply_snapshot_chunk.rs @@ -50,39 +50,39 @@ impl Default for ApplySnapshotChunkResult { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; +tendermint_pb_modules! { + use super::{ApplySnapshotChunk, ApplySnapshotChunkResult}; -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseApplySnapshotChunk { - fn from(apply_snapshot_chunk: ApplySnapshotChunk) -> Self { - Self { - result: apply_snapshot_chunk.result as i32, - refetch_chunks: apply_snapshot_chunk.refetch_chunks, - reject_senders: apply_snapshot_chunk.reject_senders, + impl From for pb::abci::ResponseApplySnapshotChunk { + fn from(apply_snapshot_chunk: ApplySnapshotChunk) -> Self { + Self { + result: apply_snapshot_chunk.result as i32, + refetch_chunks: apply_snapshot_chunk.refetch_chunks, + reject_senders: apply_snapshot_chunk.reject_senders, + } } } -} -impl TryFrom for ApplySnapshotChunk { - type Error = crate::Error; + impl TryFrom for ApplySnapshotChunk { + type Error = crate::Error; - fn try_from(apply_snapshot_chunk: pb::ResponseApplySnapshotChunk) -> Result { - let result = match apply_snapshot_chunk.result { - 0 => ApplySnapshotChunkResult::Unknown, - 1 => ApplySnapshotChunkResult::Accept, - 2 => ApplySnapshotChunkResult::Abort, - 3 => ApplySnapshotChunkResult::Retry, - 4 => ApplySnapshotChunkResult::RetrySnapshot, - 5 => ApplySnapshotChunkResult::RejectSnapshot, - _ => return Err(crate::Error::unsupported_apply_snapshot_chunk_result()), - }; - Ok(Self { - result, - refetch_chunks: apply_snapshot_chunk.refetch_chunks, - reject_senders: apply_snapshot_chunk.reject_senders, - }) + fn try_from(apply_snapshot_chunk: pb::abci::ResponseApplySnapshotChunk) -> Result { + let result = match apply_snapshot_chunk.result { + 0 => ApplySnapshotChunkResult::Unknown, + 1 => ApplySnapshotChunkResult::Accept, + 2 => ApplySnapshotChunkResult::Abort, + 3 => ApplySnapshotChunkResult::Retry, + 4 => ApplySnapshotChunkResult::RetrySnapshot, + 5 => ApplySnapshotChunkResult::RejectSnapshot, + _ => return Err(crate::Error::unsupported_apply_snapshot_chunk_result()), + }; + Ok(Self { + result, + refetch_chunks: apply_snapshot_chunk.refetch_chunks, + reject_senders: apply_snapshot_chunk.reject_senders, + }) + } } -} -impl Protobuf for ApplySnapshotChunk {} + impl Protobuf for ApplySnapshotChunk {} +} diff --git a/tendermint/src/abci/response/begin_block.rs b/tendermint/src/abci/response/begin_block.rs index 1f1622ddf..8319a116a 100644 --- a/tendermint/src/abci/response/begin_block.rs +++ b/tendermint/src/abci/response/begin_block.rs @@ -1,13 +1,10 @@ -use serde::{Deserialize, Serialize}; - use super::super::Event; use crate::prelude::*; #[doc = include_str!("../doc/response-beginblock.md")] -#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Debug, Default)] pub struct BeginBlock { /// Events that occurred while beginning the block. - #[serde(default)] pub events: Vec, } @@ -15,30 +12,30 @@ pub struct BeginBlock { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; - -use tendermint_proto::{abci as pb, Protobuf}; +tendermint_pb_modules! { + use super::BeginBlock; -impl From for pb::ResponseBeginBlock { - fn from(begin_block: BeginBlock) -> Self { - Self { - events: begin_block.events.into_iter().map(Into::into).collect(), + impl From for pb::abci::ResponseBeginBlock { + fn from(begin_block: BeginBlock) -> Self { + Self { + events: begin_block.events.into_iter().map(Into::into).collect(), + } } } -} - -impl TryFrom for BeginBlock { - type Error = crate::Error; - fn try_from(begin_block: pb::ResponseBeginBlock) -> Result { - Ok(Self { - events: begin_block - .events - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - }) + impl TryFrom for BeginBlock { + type Error = crate::Error; + + fn try_from(begin_block: pb::abci::ResponseBeginBlock) -> Result { + Ok(Self { + events: begin_block + .events + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } } -} -impl Protobuf for BeginBlock {} + impl Protobuf for BeginBlock {} +} diff --git a/tendermint/src/abci/response/check_tx.rs b/tendermint/src/abci/response/check_tx.rs index 3c730d2cf..5d41109da 100644 --- a/tendermint/src/abci/response/check_tx.rs +++ b/tendermint/src/abci/response/check_tx.rs @@ -1,13 +1,11 @@ use bytes::Bytes; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use super::super::{Code, Event}; use crate::prelude::*; -use crate::serializers; #[doc = include_str!("../doc/response-checktx.md")] -#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)] -#[serde(default)] +#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize)] pub struct CheckTx { /// The response code. /// @@ -16,7 +14,6 @@ pub struct CheckTx { /// Tendermint attributes no other value to the response code. pub code: Code, /// Result bytes, if any. - #[serde(with = "serializers::nullable")] pub data: Bytes, /// The output of the application's logger. /// @@ -27,10 +24,8 @@ pub struct CheckTx { /// **May be non-deterministic**. pub info: String, /// Amount of gas requested for the transaction. - #[serde(with = "serializers::from_str")] pub gas_wanted: i64, /// Amount of gas consumed by the transaction. - #[serde(with = "serializers::from_str")] pub gas_used: i64, /// Events that occurred while checking the transaction. pub events: Vec, @@ -39,7 +34,6 @@ pub struct CheckTx { /// The transaction's sender (e.g. the signer). pub sender: String, /// The transaction's priority (for mempool ordering). - #[serde(with = "serializers::from_str")] pub priority: i64, /// mempool_error is set by Tendermint. /// ABCI applictions should not set mempool_error. @@ -50,50 +44,50 @@ pub struct CheckTx { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; +tendermint_pb_modules! { + use super::CheckTx; -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseCheckTx { - fn from(check_tx: CheckTx) -> Self { - Self { - code: check_tx.code.into(), - data: check_tx.data, - log: check_tx.log, - info: check_tx.info, - gas_wanted: check_tx.gas_wanted, - gas_used: check_tx.gas_used, - events: check_tx.events.into_iter().map(Into::into).collect(), - codespace: check_tx.codespace, - sender: check_tx.sender, - priority: check_tx.priority, - mempool_error: check_tx.mempool_error, + impl From for pb::abci::ResponseCheckTx { + fn from(check_tx: CheckTx) -> Self { + Self { + code: check_tx.code.into(), + data: check_tx.data, + log: check_tx.log, + info: check_tx.info, + gas_wanted: check_tx.gas_wanted, + gas_used: check_tx.gas_used, + events: check_tx.events.into_iter().map(Into::into).collect(), + codespace: check_tx.codespace, + sender: check_tx.sender, + priority: check_tx.priority, + mempool_error: check_tx.mempool_error, + } } } -} -impl TryFrom for CheckTx { - type Error = crate::Error; + impl TryFrom for CheckTx { + type Error = crate::Error; - fn try_from(check_tx: pb::ResponseCheckTx) -> Result { - Ok(Self { - code: check_tx.code.into(), - data: check_tx.data, - log: check_tx.log, - info: check_tx.info, - gas_wanted: check_tx.gas_wanted, - gas_used: check_tx.gas_used, - events: check_tx - .events - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - codespace: check_tx.codespace, - sender: check_tx.sender, - priority: check_tx.priority, - mempool_error: check_tx.mempool_error, - }) + fn try_from(check_tx: pb::abci::ResponseCheckTx) -> Result { + Ok(Self { + code: check_tx.code.into(), + data: check_tx.data, + log: check_tx.log, + info: check_tx.info, + gas_wanted: check_tx.gas_wanted, + gas_used: check_tx.gas_used, + events: check_tx + .events + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + codespace: check_tx.codespace, + sender: check_tx.sender, + priority: check_tx.priority, + mempool_error: check_tx.mempool_error, + }) + } } -} -impl Protobuf for CheckTx {} + impl Protobuf for CheckTx {} +} diff --git a/tendermint/src/abci/response/commit.rs b/tendermint/src/abci/response/commit.rs index 5d6180da6..30ab4be87 100644 --- a/tendermint/src/abci/response/commit.rs +++ b/tendermint/src/abci/response/commit.rs @@ -18,28 +18,28 @@ pub struct Commit { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseCommit { - fn from(commit: Commit) -> Self { - Self { - data: commit.data, - retain_height: commit.retain_height.into(), +tendermint_pb_modules! { + use super::Commit; + + impl From for pb::abci::ResponseCommit { + fn from(commit: Commit) -> Self { + Self { + data: commit.data, + retain_height: commit.retain_height.into(), + } } } -} -impl TryFrom for Commit { - type Error = crate::Error; + impl TryFrom for Commit { + type Error = crate::Error; - fn try_from(commit: pb::ResponseCommit) -> Result { - Ok(Self { - data: commit.data, - retain_height: commit.retain_height.try_into()?, - }) + fn try_from(commit: pb::abci::ResponseCommit) -> Result { + Ok(Self { + data: commit.data, + retain_height: commit.retain_height.try_into()?, + }) + } } -} -impl Protobuf for Commit {} + impl Protobuf for Commit {} +} diff --git a/tendermint/src/abci/response/deliver_tx.rs b/tendermint/src/abci/response/deliver_tx.rs index 864461adf..f98f77624 100644 --- a/tendermint/src/abci/response/deliver_tx.rs +++ b/tendermint/src/abci/response/deliver_tx.rs @@ -1,13 +1,11 @@ use bytes::Bytes; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use super::super::{Code, Event}; use crate::prelude::*; -use crate::serializers; #[doc = include_str!("../doc/response-delivertx.md")] -#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)] -#[serde(default)] +#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize)] pub struct DeliverTx { /// The response code. /// @@ -16,7 +14,6 @@ pub struct DeliverTx { /// the application state. pub code: Code, /// Result bytes, if any. - #[serde(with = "serializers::nullable")] pub data: Bytes, /// The output of the application's logger. /// @@ -27,10 +24,8 @@ pub struct DeliverTx { /// **May be non-deterministic**. pub info: String, /// Amount of gas requested for the transaction. - #[serde(with = "serializers::from_str")] pub gas_wanted: i64, /// Amount of gas consumed by the transaction. - #[serde(with = "serializers::from_str")] pub gas_used: i64, /// Events that occurred while executing the transaction. pub events: Vec, @@ -42,44 +37,44 @@ pub struct DeliverTx { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; +tendermint_pb_modules! { + use super::DeliverTx; -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseDeliverTx { - fn from(deliver_tx: DeliverTx) -> Self { - Self { - code: deliver_tx.code.into(), - data: deliver_tx.data, - log: deliver_tx.log, - info: deliver_tx.info, - gas_wanted: deliver_tx.gas_wanted, - gas_used: deliver_tx.gas_used, - events: deliver_tx.events.into_iter().map(Into::into).collect(), - codespace: deliver_tx.codespace, + impl From for pb::abci::ResponseDeliverTx { + fn from(deliver_tx: DeliverTx) -> Self { + Self { + code: deliver_tx.code.into(), + data: deliver_tx.data, + log: deliver_tx.log, + info: deliver_tx.info, + gas_wanted: deliver_tx.gas_wanted, + gas_used: deliver_tx.gas_used, + events: deliver_tx.events.into_iter().map(Into::into).collect(), + codespace: deliver_tx.codespace, + } } } -} -impl TryFrom for DeliverTx { - type Error = crate::Error; + impl TryFrom for DeliverTx { + type Error = crate::Error; - fn try_from(deliver_tx: pb::ResponseDeliverTx) -> Result { - Ok(Self { - code: deliver_tx.code.into(), - data: deliver_tx.data, - log: deliver_tx.log, - info: deliver_tx.info, - gas_wanted: deliver_tx.gas_wanted, - gas_used: deliver_tx.gas_used, - events: deliver_tx - .events - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - codespace: deliver_tx.codespace, - }) + fn try_from(deliver_tx: pb::abci::ResponseDeliverTx) -> Result { + Ok(Self { + code: deliver_tx.code.into(), + data: deliver_tx.data, + log: deliver_tx.log, + info: deliver_tx.info, + gas_wanted: deliver_tx.gas_wanted, + gas_used: deliver_tx.gas_used, + events: deliver_tx + .events + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + codespace: deliver_tx.codespace, + }) + } } -} -impl Protobuf for DeliverTx {} + impl Protobuf for DeliverTx {} +} diff --git a/tendermint/src/abci/response/echo.rs b/tendermint/src/abci/response/echo.rs index 7e4777713..11daa5276 100644 --- a/tendermint/src/abci/response/echo.rs +++ b/tendermint/src/abci/response/echo.rs @@ -11,26 +11,26 @@ pub struct Echo { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseEcho { - fn from(echo: Echo) -> Self { - Self { - message: echo.message, +tendermint_pb_modules! { + use super::Echo; + + impl From for pb::abci::ResponseEcho { + fn from(echo: Echo) -> Self { + Self { + message: echo.message, + } } } -} -impl TryFrom for Echo { - type Error = crate::Error; + impl TryFrom for Echo { + type Error = crate::Error; - fn try_from(echo: pb::ResponseEcho) -> Result { - Ok(Self { - message: echo.message, - }) + fn try_from(echo: pb::abci::ResponseEcho) -> Result { + Ok(Self { + message: echo.message, + }) + } } -} -impl Protobuf for Echo {} + impl Protobuf for Echo {} +} diff --git a/tendermint/src/abci/response/end_block.rs b/tendermint/src/abci/response/end_block.rs index 4b4463cee..ce2b9950f 100644 --- a/tendermint/src/abci/response/end_block.rs +++ b/tendermint/src/abci/response/end_block.rs @@ -1,20 +1,16 @@ -use serde::{Deserialize, Serialize}; - use super::super::Event; -use crate::{consensus, prelude::*, serializers, validator}; +use crate::{consensus, prelude::*, validator}; #[doc = include_str!("../doc/response-endblock.md")] -#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Debug, Default)] pub struct EndBlock { /// Changes to the validator set, if any. /// /// Setting the voting power to 0 removes a validator. - #[serde(with = "serializers::nullable")] pub validator_updates: Vec, /// Changes to consensus parameters (optional). pub consensus_param_updates: Option, /// Events that occurred while ending the block. - #[serde(default)] pub events: Vec, } @@ -22,45 +18,45 @@ pub struct EndBlock { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseEndBlock { - fn from(end_block: EndBlock) -> Self { - Self { - validator_updates: end_block - .validator_updates - .into_iter() - .map(Into::into) - .collect(), - consensus_param_updates: end_block.consensus_param_updates.map(Into::into), - events: end_block.events.into_iter().map(Into::into).collect(), +tendermint_pb_modules! { + use super::EndBlock; + + impl From for pb::abci::ResponseEndBlock { + fn from(end_block: EndBlock) -> Self { + Self { + validator_updates: end_block + .validator_updates + .into_iter() + .map(Into::into) + .collect(), + consensus_param_updates: end_block.consensus_param_updates.map(Into::into), + events: end_block.events.into_iter().map(Into::into).collect(), + } } } -} -impl TryFrom for EndBlock { - type Error = crate::Error; - - fn try_from(end_block: pb::ResponseEndBlock) -> Result { - Ok(Self { - validator_updates: end_block - .validator_updates - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - consensus_param_updates: end_block - .consensus_param_updates - .map(TryInto::try_into) - .transpose()?, - events: end_block - .events - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - }) + impl TryFrom for EndBlock { + type Error = crate::Error; + + fn try_from(end_block: pb::abci::ResponseEndBlock) -> Result { + Ok(Self { + validator_updates: end_block + .validator_updates + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + consensus_param_updates: end_block + .consensus_param_updates + .map(TryInto::try_into) + .transpose()?, + events: end_block + .events + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } } -} -impl Protobuf for EndBlock {} + impl Protobuf for EndBlock {} +} diff --git a/tendermint/src/abci/response/exception.rs b/tendermint/src/abci/response/exception.rs index a6e784147..d8035173d 100644 --- a/tendermint/src/abci/response/exception.rs +++ b/tendermint/src/abci/response/exception.rs @@ -11,26 +11,26 @@ pub struct Exception { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseException { - fn from(exception: Exception) -> Self { - Self { - error: exception.error, +tendermint_pb_modules! { + use super::Exception; + + impl From for pb::abci::ResponseException { + fn from(exception: Exception) -> Self { + Self { + error: exception.error, + } } } -} -impl TryFrom for Exception { - type Error = crate::Error; + impl TryFrom for Exception { + type Error = crate::Error; - fn try_from(exception: pb::ResponseException) -> Result { - Ok(Self { - error: exception.error, - }) + fn try_from(exception: pb::abci::ResponseException) -> Result { + Ok(Self { + error: exception.error, + }) + } } -} -impl Protobuf for Exception {} + impl Protobuf for Exception {} +} diff --git a/tendermint/src/abci/response/info.rs b/tendermint/src/abci/response/info.rs index b19705599..af2b98cea 100644 --- a/tendermint/src/abci/response/info.rs +++ b/tendermint/src/abci/response/info.rs @@ -1,7 +1,5 @@ -use crate::{block, prelude::*, AppHash, Error}; -use core::convert::TryFrom; -use tendermint_proto::abci as pb; -use tendermint_proto::Protobuf; +use crate::{block, prelude::*, AppHash}; +use tendermint_proto::v0_37::abci as pb; use serde::{Deserialize, Serialize}; @@ -25,30 +23,34 @@ pub struct Info { // Protobuf conversions // ============================================================================= -impl From for pb::ResponseInfo { - fn from(info: Info) -> Self { - Self { - data: info.data, - version: info.version, - app_version: info.app_version, - last_block_height: info.last_block_height.into(), - last_block_app_hash: info.last_block_app_hash.into(), +tendermint_pb_modules! { + use super::Info; + + impl From for pb::abci::ResponseInfo { + fn from(info: Info) -> Self { + Self { + data: info.data, + version: info.version, + app_version: info.app_version, + last_block_height: info.last_block_height.into(), + last_block_app_hash: info.last_block_app_hash.into(), + } } } -} -impl TryFrom for Info { - type Error = Error; - - fn try_from(info: pb::ResponseInfo) -> Result { - Ok(Self { - data: info.data, - version: info.version, - app_version: info.app_version, - last_block_height: info.last_block_height.try_into()?, - last_block_app_hash: info.last_block_app_hash.try_into()?, - }) + impl TryFrom for Info { + type Error = crate::Error; + + fn try_from(info: pb::abci::ResponseInfo) -> Result { + Ok(Self { + data: info.data, + version: info.version, + app_version: info.app_version, + last_block_height: info.last_block_height.try_into()?, + last_block_app_hash: info.last_block_app_hash.try_into()?, + }) + } } -} -impl Protobuf for Info {} + impl Protobuf for Info {} +} diff --git a/tendermint/src/abci/response/init_chain.rs b/tendermint/src/abci/response/init_chain.rs index 0dc360c0b..c4a9946a3 100644 --- a/tendermint/src/abci/response/init_chain.rs +++ b/tendermint/src/abci/response/init_chain.rs @@ -24,37 +24,37 @@ pub struct InitChain { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseInitChain { - fn from(init_chain: InitChain) -> Self { - Self { - consensus_params: init_chain.consensus_params.map(Into::into), - validators: init_chain.validators.into_iter().map(Into::into).collect(), - app_hash: init_chain.app_hash.into(), +tendermint_pb_modules! { + use super::InitChain; + + impl From for pb::abci::ResponseInitChain { + fn from(init_chain: InitChain) -> Self { + Self { + consensus_params: init_chain.consensus_params.map(Into::into), + validators: init_chain.validators.into_iter().map(Into::into).collect(), + app_hash: init_chain.app_hash.into(), + } } } -} -impl TryFrom for InitChain { - type Error = crate::Error; - - fn try_from(init_chain: pb::ResponseInitChain) -> Result { - Ok(Self { - consensus_params: init_chain - .consensus_params - .map(TryInto::try_into) - .transpose()?, - validators: init_chain - .validators - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - app_hash: init_chain.app_hash.try_into()?, - }) + impl TryFrom for InitChain { + type Error = crate::Error; + + fn try_from(init_chain: pb::abci::ResponseInitChain) -> Result { + Ok(Self { + consensus_params: init_chain + .consensus_params + .map(TryInto::try_into) + .transpose()?, + validators: init_chain + .validators + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + app_hash: init_chain.app_hash.try_into()?, + }) + } } -} -impl Protobuf for InitChain {} + impl Protobuf for InitChain {} +} diff --git a/tendermint/src/abci/response/list_snapshots.rs b/tendermint/src/abci/response/list_snapshots.rs index 55a7a5f24..e195687e8 100644 --- a/tendermint/src/abci/response/list_snapshots.rs +++ b/tendermint/src/abci/response/list_snapshots.rs @@ -12,34 +12,34 @@ pub struct ListSnapshots { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseListSnapshots { - fn from(list_snapshots: ListSnapshots) -> Self { - Self { - snapshots: list_snapshots - .snapshots - .into_iter() - .map(Into::into) - .collect(), +tendermint_pb_modules! { + use super::ListSnapshots; + + impl From for pb::abci::ResponseListSnapshots { + fn from(list_snapshots: ListSnapshots) -> Self { + Self { + snapshots: list_snapshots + .snapshots + .into_iter() + .map(Into::into) + .collect(), + } } } -} - -impl TryFrom for ListSnapshots { - type Error = crate::Error; - fn try_from(list_snapshots: pb::ResponseListSnapshots) -> Result { - Ok(Self { - snapshots: list_snapshots - .snapshots - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - }) + impl TryFrom for ListSnapshots { + type Error = crate::Error; + + fn try_from(list_snapshots: pb::abci::ResponseListSnapshots) -> Result { + Ok(Self { + snapshots: list_snapshots + .snapshots + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } } -} -impl Protobuf for ListSnapshots {} + impl Protobuf for ListSnapshots {} +} diff --git a/tendermint/src/abci/response/load_snapshot_chunk.rs b/tendermint/src/abci/response/load_snapshot_chunk.rs index fb8f2c129..05546dc86 100644 --- a/tendermint/src/abci/response/load_snapshot_chunk.rs +++ b/tendermint/src/abci/response/load_snapshot_chunk.rs @@ -16,26 +16,26 @@ pub struct LoadSnapshotChunk { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseLoadSnapshotChunk { - fn from(load_snapshot_chunk: LoadSnapshotChunk) -> Self { - Self { - chunk: load_snapshot_chunk.chunk, +tendermint_pb_modules! { + use super::LoadSnapshotChunk; + + impl From for pb::abci::ResponseLoadSnapshotChunk { + fn from(load_snapshot_chunk: LoadSnapshotChunk) -> Self { + Self { + chunk: load_snapshot_chunk.chunk, + } } } -} -impl TryFrom for LoadSnapshotChunk { - type Error = crate::Error; + impl TryFrom for LoadSnapshotChunk { + type Error = crate::Error; - fn try_from(load_snapshot_chunk: pb::ResponseLoadSnapshotChunk) -> Result { - Ok(Self { - chunk: load_snapshot_chunk.chunk, - }) + fn try_from(load_snapshot_chunk: pb::abci::ResponseLoadSnapshotChunk) -> Result { + Ok(Self { + chunk: load_snapshot_chunk.chunk, + }) + } } -} -impl Protobuf for LoadSnapshotChunk {} + impl Protobuf for LoadSnapshotChunk {} +} diff --git a/tendermint/src/abci/response/offer_snapshot.rs b/tendermint/src/abci/response/offer_snapshot.rs index 47ee38861..97e3660ab 100644 --- a/tendermint/src/abci/response/offer_snapshot.rs +++ b/tendermint/src/abci/response/offer_snapshot.rs @@ -31,32 +31,32 @@ impl Default for OfferSnapshot { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; - -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseOfferSnapshot { - fn from(offer_snapshot: OfferSnapshot) -> Self { - Self { - result: offer_snapshot as i32, +tendermint_pb_modules! { + use super::OfferSnapshot; + + impl From for pb::abci::ResponseOfferSnapshot { + fn from(offer_snapshot: OfferSnapshot) -> Self { + Self { + result: offer_snapshot as i32, + } } } -} -impl TryFrom for OfferSnapshot { - type Error = crate::Error; - - fn try_from(offer_snapshot: pb::ResponseOfferSnapshot) -> Result { - Ok(match offer_snapshot.result { - 0 => OfferSnapshot::Unknown, - 1 => OfferSnapshot::Accept, - 2 => OfferSnapshot::Abort, - 3 => OfferSnapshot::Reject, - 4 => OfferSnapshot::RejectFormat, - 5 => OfferSnapshot::RejectSender, - _ => return Err(crate::Error::unsupported_offer_snapshot_chunk_result()), - }) + impl TryFrom for OfferSnapshot { + type Error = crate::Error; + + fn try_from(offer_snapshot: pb::abci::ResponseOfferSnapshot) -> Result { + Ok(match offer_snapshot.result { + 0 => OfferSnapshot::Unknown, + 1 => OfferSnapshot::Accept, + 2 => OfferSnapshot::Abort, + 3 => OfferSnapshot::Reject, + 4 => OfferSnapshot::RejectFormat, + 5 => OfferSnapshot::RejectSender, + _ => return Err(crate::Error::unsupported_offer_snapshot_chunk_result()), + }) + } } -} -impl Protobuf for OfferSnapshot {} + impl Protobuf for OfferSnapshot {} +} diff --git a/tendermint/src/abci/response/prepare_proposal.rs b/tendermint/src/abci/response/prepare_proposal.rs new file mode 100644 index 000000000..d8facfed5 --- /dev/null +++ b/tendermint/src/abci/response/prepare_proposal.rs @@ -0,0 +1,34 @@ +use bytes::Bytes; + +use crate::prelude::*; + +#[doc = include_str!("../doc/response-prepareproposal.md")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct PrepareProposal { + pub txs: Vec, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +// PrepareProposal has been introduced in 0.37. + +use tendermint_proto::v0_37::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponsePrepareProposal { + fn from(value: PrepareProposal) -> Self { + Self { txs: value.txs } + } +} + +impl TryFrom for PrepareProposal { + type Error = crate::Error; + + fn try_from(message: pb::ResponsePrepareProposal) -> Result { + Ok(Self { txs: message.txs }) + } +} + +impl Protobuf for PrepareProposal {} diff --git a/tendermint/src/abci/response/process_proposal.rs b/tendermint/src/abci/response/process_proposal.rs new file mode 100644 index 000000000..acaf45ef9 --- /dev/null +++ b/tendermint/src/abci/response/process_proposal.rs @@ -0,0 +1,91 @@ +use crate::prelude::*; + +#[doc = include_str!("../doc/response-processproposal.md")] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(i32)] +pub enum ProcessProposal { + Unknown = 0, + Accept = 1, + Reject = 2, +} + +impl Default for ProcessProposal { + #[inline] + fn default() -> Self { + ProcessProposal::Unknown + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +// ProcessProposal has been introduced in 0.37. + +use tendermint_proto::v0_37::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseProcessProposal { + fn from(value: ProcessProposal) -> Self { + Self { + status: value as i32, + } + } +} + +impl TryFrom for ProcessProposal { + type Error = crate::Error; + + fn try_from(message: pb::ResponseProcessProposal) -> Result { + let value = match message.status { + 0 => ProcessProposal::Unknown, + 1 => ProcessProposal::Accept, + 2 => ProcessProposal::Reject, + _ => return Err(crate::Error::unsupported_process_proposal_status()), + }; + Ok(value) + } +} + +impl Protobuf for ProcessProposal {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::error::ErrorDetail; + + use std::collections::HashMap; + + #[test] + fn all_status_values_are_covered() { + use pb::response_process_proposal::ProposalStatus::*; + + const FIRST_INVALID_STATUS: i32 = 3; + + let mut covered = HashMap::new(); + for v in [Unknown, Accept, Reject] { + // Match the generated enum values exhaustively + match v { + Unknown | Accept | Reject => { + covered.insert(v as i32, false); + }, + } + } + for status in 0..FIRST_INVALID_STATUS { + let message = pb::ResponseProcessProposal { status }; + let response: ProcessProposal = message.try_into().unwrap(); + assert_eq!(response as i32, status); + covered.insert(status, true); + } + assert!(covered.values().all(|&x| x)); + + let message = pb::ResponseProcessProposal { + status: FIRST_INVALID_STATUS, + }; + let err = ProcessProposal::try_from(message).err().unwrap(); + assert!(matches!( + err.0, + ErrorDetail::UnsupportedProcessProposalStatus(_), + )); + } +} diff --git a/tendermint/src/abci/response/query.rs b/tendermint/src/abci/response/query.rs index 40fbc8beb..23bbe8b83 100644 --- a/tendermint/src/abci/response/query.rs +++ b/tendermint/src/abci/response/query.rs @@ -40,42 +40,42 @@ pub struct Query { // Protobuf conversions // ============================================================================= -use core::convert::{TryFrom, TryInto}; +tendermint_pb_modules! { + use super::Query; -use tendermint_proto::{abci as pb, Protobuf}; - -impl From for pb::ResponseQuery { - fn from(query: Query) -> Self { - Self { - code: query.code.into(), - log: query.log, - info: query.info, - index: query.index, - key: query.key, - value: query.value, - proof_ops: query.proof.map(Into::into), - height: query.height.into(), - codespace: query.codespace, + impl From for pb::abci::ResponseQuery { + fn from(query: Query) -> Self { + Self { + code: query.code.into(), + log: query.log, + info: query.info, + index: query.index, + key: query.key, + value: query.value, + proof_ops: query.proof.map(Into::into), + height: query.height.into(), + codespace: query.codespace, + } } } -} -impl TryFrom for Query { - type Error = crate::Error; + impl TryFrom for Query { + type Error = crate::Error; - fn try_from(query: pb::ResponseQuery) -> Result { - Ok(Self { - code: query.code.into(), - log: query.log, - info: query.info, - index: query.index, - key: query.key, - value: query.value, - proof: query.proof_ops.map(TryInto::try_into).transpose()?, - height: query.height.try_into()?, - codespace: query.codespace, - }) + fn try_from(query: pb::abci::ResponseQuery) -> Result { + Ok(Self { + code: query.code.into(), + log: query.log, + info: query.info, + index: query.index, + key: query.key, + value: query.value, + proof: query.proof_ops.map(TryInto::try_into).transpose()?, + height: query.height.try_into()?, + codespace: query.codespace, + }) + } } -} -impl Protobuf for Query {} + impl Protobuf for Query {} +} diff --git a/tendermint/src/abci/response/set_option.rs b/tendermint/src/abci/response/set_option.rs index 028eafde5..98399dbb1 100644 --- a/tendermint/src/abci/response/set_option.rs +++ b/tendermint/src/abci/response/set_option.rs @@ -13,9 +13,10 @@ pub struct SetOption { // Protobuf conversions // ============================================================================= -use core::convert::TryFrom; +// The SetOption request has been removed after 0.34. -use tendermint_proto::{abci as pb, Protobuf}; +use tendermint_proto::v0_34::abci as pb; +use tendermint_proto::Protobuf; impl From for pb::ResponseSetOption { fn from(message: SetOption) -> Self { diff --git a/tendermint/src/abci/types.rs b/tendermint/src/abci/types.rs index 11f8afa28..6aeaf7536 100644 --- a/tendermint/src/abci/types.rs +++ b/tendermint/src/abci/types.rs @@ -5,11 +5,9 @@ //! //! [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#data-types) -use core::convert::{TryFrom, TryInto}; - use bytes::Bytes; -use crate::{block, prelude::*, vote, Error, Time}; +use crate::{block, prelude::*, vote, Time}; /// A validator address with voting power. /// @@ -33,15 +31,15 @@ pub struct VoteInfo { pub signed_last_block: bool, } -/// The possible kinds of [`Evidence`]. +/// The possible kinds of [`Misbehavior`]. /// /// Note: the -/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#evidencetype-2) -/// calls this `EvidenceType`, but we follow the Rust convention and name it `EvidenceKind` +/// [ABCI documentation](https://github.com/tendermint/tendermint/blob/main/spec/abci/abci++_methods.md#misbehaviortype) +/// calls this `MisbehaviorType`, but we follow the Rust convention and name it `MisbehaviorKind` /// to avoid confusion with Rust types. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[repr(i32)] -pub enum EvidenceKind { +pub enum MisbehaviorKind { /// Unknown evidence type (proto default value). Unknown = 0, /// Evidence that the validator voted for two different blocks in the same @@ -55,12 +53,12 @@ pub enum EvidenceKind { /// /// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#evidence) #[derive(Clone, PartialEq, Eq, Debug)] -pub struct Evidence { +pub struct Misbehavior { /// The kind of evidence. /// /// Note: this field is called `type` in the protobuf, but we call it `kind` /// to avoid the Rust keyword. - pub kind: EvidenceKind, + pub kind: MisbehaviorKind, /// The offending validator. pub validator: Validator, /// The height when the offense occurred. @@ -75,11 +73,11 @@ pub struct Evidence { pub total_voting_power: vote::Power, } -/// Information on the last block commit. +/// Information on a block commit. /// -/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#lastcommitinfo) +/// [ABCI documentation](https://github.com/tendermint/tendermint/blob/main/spec/abci/abci++_methods.md#extendedcommitinfo) #[derive(Clone, PartialEq, Eq, Debug)] -pub struct LastCommitInfo { +pub struct CommitInfo { /// The commit round. /// /// Reflects the total number of rounds it took to come to consensus for the @@ -120,154 +118,378 @@ pub struct Snapshot { // Protobuf conversions // ============================================================================= -use tendermint_proto::{abci as pb, Protobuf}; +mod v0_34 { + use super::{CommitInfo, Misbehavior, MisbehaviorKind, Snapshot, Validator, VoteInfo}; + use crate::{prelude::*, Error}; + use tendermint_proto::v0_34::abci as pb; + use tendermint_proto::Protobuf; + + use bytes::Bytes; -impl From for pb::Validator { - fn from(v: Validator) -> Self { - Self { - address: Bytes::copy_from_slice(&v.address[..]), - power: v.power.into(), + impl From for pb::Validator { + fn from(v: Validator) -> Self { + Self { + address: Bytes::copy_from_slice(&v.address[..]), + power: v.power.into(), + } } } -} -impl TryFrom for Validator { - type Error = Error; - - fn try_from(vu: pb::Validator) -> Result { - let address = if vu.address.len() == 20 { - let mut bytes = [0u8; 20]; - bytes.copy_from_slice(&vu.address); - bytes - } else { - return Err(Error::invalid_account_id_length()); - }; - - Ok(Self { - address, - power: vu.power.try_into()?, - }) + impl TryFrom for Validator { + type Error = Error; + + fn try_from(vu: pb::Validator) -> Result { + let address = if vu.address.len() == 20 { + let mut bytes = [0u8; 20]; + bytes.copy_from_slice(&vu.address); + bytes + } else { + return Err(Error::invalid_account_id_length()); + }; + + Ok(Self { + address, + power: vu.power.try_into()?, + }) + } } -} -impl Protobuf for Validator {} + impl Protobuf for Validator {} -impl From for pb::VoteInfo { - fn from(vi: VoteInfo) -> Self { - Self { - validator: Some(vi.validator.into()), - signed_last_block: vi.signed_last_block, + impl From for pb::VoteInfo { + fn from(vi: VoteInfo) -> Self { + Self { + validator: Some(vi.validator.into()), + signed_last_block: vi.signed_last_block, + } } } -} -impl TryFrom for VoteInfo { - type Error = Error; - - fn try_from(vi: pb::VoteInfo) -> Result { - Ok(Self { - validator: vi - .validator - .ok_or_else(Error::missing_validator)? - .try_into()?, - signed_last_block: vi.signed_last_block, - }) + impl TryFrom for VoteInfo { + type Error = Error; + + fn try_from(vi: pb::VoteInfo) -> Result { + Ok(Self { + validator: vi + .validator + .ok_or_else(Error::missing_validator)? + .try_into()?, + signed_last_block: vi.signed_last_block, + }) + } } -} -impl Protobuf for VoteInfo {} + impl Protobuf for VoteInfo {} + + impl From for pb::Evidence { + fn from(evidence: Misbehavior) -> Self { + Self { + r#type: evidence.kind as i32, + validator: Some(evidence.validator.into()), + height: evidence.height.into(), + time: Some(evidence.time.into()), + total_voting_power: evidence.total_voting_power.into(), + } + } + } -impl From for pb::Evidence { - fn from(evidence: Evidence) -> Self { - Self { - r#type: evidence.kind as i32, - validator: Some(evidence.validator.into()), - height: evidence.height.into(), - time: Some(evidence.time.into()), - total_voting_power: evidence.total_voting_power.into(), + impl TryFrom for Misbehavior { + type Error = Error; + + fn try_from(evidence: pb::Evidence) -> Result { + let kind = match evidence.r#type { + 0 => MisbehaviorKind::Unknown, + 1 => MisbehaviorKind::DuplicateVote, + 2 => MisbehaviorKind::LightClientAttack, + _ => return Err(Error::invalid_evidence()), + }; + + Ok(Self { + kind, + validator: evidence + .validator + .ok_or_else(Error::missing_validator)? + .try_into()?, + height: evidence.height.try_into()?, + time: evidence + .time + .ok_or_else(Error::missing_timestamp)? + .try_into()?, + total_voting_power: evidence.total_voting_power.try_into()?, + }) } } -} -impl TryFrom for Evidence { - type Error = Error; - - fn try_from(evidence: pb::Evidence) -> Result { - let kind = match evidence.r#type { - 0 => EvidenceKind::Unknown, - 1 => EvidenceKind::DuplicateVote, - 2 => EvidenceKind::LightClientAttack, - _ => return Err(Error::invalid_evidence()), - }; - - Ok(Self { - kind, - validator: evidence - .validator - .ok_or_else(Error::missing_validator)? - .try_into()?, - height: evidence.height.try_into()?, - time: evidence - .time - .ok_or_else(Error::missing_timestamp)? - .try_into()?, - total_voting_power: evidence.total_voting_power.try_into()?, - }) + impl Protobuf for Misbehavior {} + + impl From for pb::LastCommitInfo { + fn from(lci: CommitInfo) -> Self { + Self { + round: lci.round.into(), + votes: lci.votes.into_iter().map(Into::into).collect(), + } + } } -} -impl Protobuf for Evidence {} + impl TryFrom for CommitInfo { + type Error = Error; + + fn try_from(lci: pb::LastCommitInfo) -> Result { + Ok(Self { + round: lci.round.try_into()?, + votes: lci + .votes + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } + } -impl From for pb::LastCommitInfo { - fn from(lci: LastCommitInfo) -> Self { - Self { - round: lci.round.into(), - votes: lci.votes.into_iter().map(Into::into).collect(), + impl Protobuf for CommitInfo {} + + impl From for pb::Snapshot { + fn from(snapshot: Snapshot) -> Self { + Self { + height: snapshot.height.into(), + format: snapshot.format, + chunks: snapshot.chunks, + hash: snapshot.hash, + metadata: snapshot.metadata, + } } } -} -impl TryFrom for LastCommitInfo { - type Error = Error; - - fn try_from(lci: pb::LastCommitInfo) -> Result { - Ok(Self { - round: lci.round.try_into()?, - votes: lci - .votes - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - }) + impl TryFrom for Snapshot { + type Error = Error; + + fn try_from(snapshot: pb::Snapshot) -> Result { + Ok(Self { + height: snapshot.height.try_into()?, + format: snapshot.format, + chunks: snapshot.chunks, + hash: snapshot.hash, + metadata: snapshot.metadata, + }) + } } + + impl Protobuf for Snapshot {} } -impl Protobuf for LastCommitInfo {} +mod v0_37 { + use super::{CommitInfo, Misbehavior, MisbehaviorKind, Snapshot, Validator, VoteInfo}; + use crate::{prelude::*, Error}; + use tendermint_proto::v0_37::abci as pb; + use tendermint_proto::Protobuf; -impl From for pb::Snapshot { - fn from(snapshot: Snapshot) -> Self { - Self { - height: snapshot.height.into(), - format: snapshot.format, - chunks: snapshot.chunks, - hash: snapshot.hash, - metadata: snapshot.metadata, + use bytes::Bytes; + + impl From for pb::Validator { + fn from(v: Validator) -> Self { + Self { + address: Bytes::copy_from_slice(&v.address[..]), + power: v.power.into(), + } } } -} -impl TryFrom for Snapshot { - type Error = Error; - - fn try_from(snapshot: pb::Snapshot) -> Result { - Ok(Self { - height: snapshot.height.try_into()?, - format: snapshot.format, - chunks: snapshot.chunks, - hash: snapshot.hash, - metadata: snapshot.metadata, - }) + impl TryFrom for Validator { + type Error = Error; + + fn try_from(vu: pb::Validator) -> Result { + let address = if vu.address.len() == 20 { + let mut bytes = [0u8; 20]; + bytes.copy_from_slice(&vu.address); + bytes + } else { + return Err(Error::invalid_account_id_length()); + }; + + Ok(Self { + address, + power: vu.power.try_into()?, + }) + } + } + + impl Protobuf for Validator {} + + impl From for pb::VoteInfo { + fn from(vi: VoteInfo) -> Self { + Self { + validator: Some(vi.validator.into()), + signed_last_block: vi.signed_last_block, + } + } + } + + impl TryFrom for VoteInfo { + type Error = Error; + + fn try_from(vi: pb::VoteInfo) -> Result { + Ok(Self { + validator: vi + .validator + .ok_or_else(Error::missing_validator)? + .try_into()?, + signed_last_block: vi.signed_last_block, + }) + } + } + + impl Protobuf for VoteInfo {} + + // ExtendedVoteInfo is defined in 0.37, but the vote_extension field is always nil, + // so we can omit it from VoteInfo for the time being. + + impl From for pb::ExtendedVoteInfo { + fn from(vi: VoteInfo) -> Self { + Self { + validator: Some(vi.validator.into()), + signed_last_block: vi.signed_last_block, + vote_extension: Default::default(), + } + } + } + + impl TryFrom for VoteInfo { + type Error = Error; + + fn try_from(vi: pb::ExtendedVoteInfo) -> Result { + Ok(Self { + validator: vi + .validator + .ok_or_else(Error::missing_validator)? + .try_into()?, + signed_last_block: vi.signed_last_block, + }) + } } -} -impl Protobuf for Snapshot {} + impl Protobuf for VoteInfo {} + + impl From for pb::Misbehavior { + fn from(evidence: Misbehavior) -> Self { + Self { + r#type: evidence.kind as i32, + validator: Some(evidence.validator.into()), + height: evidence.height.into(), + time: Some(evidence.time.into()), + total_voting_power: evidence.total_voting_power.into(), + } + } + } + + impl TryFrom for Misbehavior { + type Error = Error; + + fn try_from(evidence: pb::Misbehavior) -> Result { + let kind = match evidence.r#type { + 0 => MisbehaviorKind::Unknown, + 1 => MisbehaviorKind::DuplicateVote, + 2 => MisbehaviorKind::LightClientAttack, + _ => return Err(Error::invalid_evidence()), + }; + + Ok(Self { + kind, + validator: evidence + .validator + .ok_or_else(Error::missing_validator)? + .try_into()?, + height: evidence.height.try_into()?, + time: evidence + .time + .ok_or_else(Error::missing_timestamp)? + .try_into()?, + total_voting_power: evidence.total_voting_power.try_into()?, + }) + } + } + + impl Protobuf for Misbehavior {} + + // The CommitInfo domain type represents both CommitInfo and ExtendedCommitInfo + // as defined in protobuf for 0.37. + + impl From for pb::CommitInfo { + fn from(lci: CommitInfo) -> Self { + Self { + round: lci.round.into(), + votes: lci.votes.into_iter().map(Into::into).collect(), + } + } + } + + impl TryFrom for CommitInfo { + type Error = Error; + + fn try_from(lci: pb::CommitInfo) -> Result { + Ok(Self { + round: lci.round.try_into()?, + votes: lci + .votes + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } + } + + impl Protobuf for CommitInfo {} + + impl From for pb::ExtendedCommitInfo { + fn from(lci: CommitInfo) -> Self { + Self { + round: lci.round.into(), + votes: lci.votes.into_iter().map(Into::into).collect(), + } + } + } + + impl TryFrom for CommitInfo { + type Error = Error; + + fn try_from(lci: pb::ExtendedCommitInfo) -> Result { + Ok(Self { + round: lci.round.try_into()?, + votes: lci + .votes + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } + } + + impl Protobuf for CommitInfo {} + + impl From for pb::Snapshot { + fn from(snapshot: Snapshot) -> Self { + Self { + height: snapshot.height.into(), + format: snapshot.format, + chunks: snapshot.chunks, + hash: snapshot.hash, + metadata: snapshot.metadata, + } + } + } + + impl TryFrom for Snapshot { + type Error = Error; + + fn try_from(snapshot: pb::Snapshot) -> Result { + Ok(Self { + height: snapshot.height.try_into()?, + format: snapshot.format, + chunks: snapshot.chunks, + hash: snapshot.hash, + metadata: snapshot.metadata, + }) + } + } + + impl Protobuf for Snapshot {} +} diff --git a/tendermint/src/account.rs b/tendermint/src/account.rs index fc4ccbfa7..473c97271 100644 --- a/tendermint/src/account.rs +++ b/tendermint/src/account.rs @@ -6,9 +6,11 @@ use core::{ str::FromStr, }; +use bytes::Bytes; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use subtle::{self, ConstantTimeEq}; use subtle_encoding::hex; + use tendermint_proto::Protobuf; use crate::{error::Error, prelude::*}; @@ -41,6 +43,25 @@ impl From for Vec { } } +impl TryFrom for Id { + type Error = Error; + + fn try_from(value: Bytes) -> Result { + if value.len() != LENGTH { + return Err(Error::invalid_account_id_length()); + } + let mut slice: [u8; LENGTH] = [0; LENGTH]; + slice.copy_from_slice(&value[..]); + Ok(Id(slice)) + } +} + +impl From for Bytes { + fn from(value: Id) -> Self { + Bytes::copy_from_slice(value.as_bytes()) + } +} + impl Id { /// Create a new account ID from raw bytes pub fn new(bytes: [u8; LENGTH]) -> Id { diff --git a/tendermint/src/block.rs b/tendermint/src/block.rs index 0f961c05c..f0471c598 100644 --- a/tendermint/src/block.rs +++ b/tendermint/src/block.rs @@ -11,10 +11,8 @@ mod round; pub mod signed_header; mod size; -use core::convert::{TryFrom, TryInto}; - use serde::{Deserialize, Serialize}; -use tendermint_proto::{types::Block as RawBlock, Protobuf}; +use tendermint_proto::v0_37::types::Block as RawBlock; pub use self::{ commit::*, @@ -50,49 +48,55 @@ pub struct Block { pub last_commit: Option, } -impl Protobuf for Block {} - -impl TryFrom for Block { - type Error = Error; - - fn try_from(value: RawBlock) -> Result { - let header: Header = value.header.ok_or_else(Error::missing_header)?.try_into()?; - // if last_commit is Commit::Default, it is considered nil by Go. - let last_commit = value - .last_commit - .map(TryInto::try_into) - .transpose()? - .filter(|c| c != &Commit::default()); - if last_commit.is_none() && header.height.value() != 1 { - return Err(Error::invalid_block( - "last_commit is empty on non-first block".to_string(), - )); +tendermint_pb_modules! { + use super::{Block, Header, Commit}; + use crate::{Error, prelude::*}; + use pb::types::Block as RawBlock; + + impl Protobuf for Block {} + + impl TryFrom for Block { + type Error = Error; + + fn try_from(value: RawBlock) -> Result { + let header: Header = value.header.ok_or_else(Error::missing_header)?.try_into()?; + // if last_commit is Commit::Default, it is considered nil by Go. + let last_commit = value + .last_commit + .map(TryInto::try_into) + .transpose()? + .filter(|c| c != &Commit::default()); + if last_commit.is_none() && header.height.value() != 1 { + return Err(Error::invalid_block( + "last_commit is empty on non-first block".to_string(), + )); + } + // Todo: Figure out requirements. + // if last_commit.is_some() && header.height.value() == 1 { + // return Err(Kind::InvalidFirstBlock.context("last_commit is not null on first + // height").into()); + //} + Ok(Block { + header, + data: value.data.ok_or_else(Error::missing_data)?.txs, + evidence: value + .evidence + .ok_or_else(Error::missing_evidence)? + .try_into()?, + last_commit, + }) } - // Todo: Figure out requirements. - // if last_commit.is_some() && header.height.value() == 1 { - // return Err(Kind::InvalidFirstBlock.context("last_commit is not null on first - // height").into()); - //} - Ok(Block { - header, - data: value.data.ok_or_else(Error::missing_data)?.txs, - evidence: value - .evidence - .ok_or_else(Error::missing_evidence)? - .try_into()?, - last_commit, - }) } -} -impl From for RawBlock { - fn from(value: Block) -> Self { - use tendermint_proto::types::Data as RawData; - RawBlock { - header: Some(value.header.into()), - data: Some(RawData { txs: value.data }), - evidence: Some(value.evidence.into()), - last_commit: value.last_commit.map(Into::into), + impl From for RawBlock { + fn from(value: Block) -> Self { + use pb::types::Data as RawData; + RawBlock { + header: Some(value.header.into()), + data: Some(RawData { txs: value.data }), + evidence: Some(value.evidence.into()), + last_commit: value.last_commit.map(Into::into), + } } } } diff --git a/tendermint/src/block/commit.rs b/tendermint/src/block/commit.rs index 2672a9efd..2a14e5bc0 100644 --- a/tendermint/src/block/commit.rs +++ b/tendermint/src/block/commit.rs @@ -1,13 +1,10 @@ //! Commits to a Tendermint blockchain -use core::convert::{TryFrom, TryInto}; - use serde::{Deserialize, Serialize}; -use tendermint_proto::types::Commit as RawCommit; +use tendermint_proto::v0_37::types::Commit as RawCommit; use crate::{ block::{commit_sig::CommitSig, Height, Id, Round}, - error::Error, prelude::*, }; @@ -32,34 +29,44 @@ pub struct Commit { pub signatures: Vec, } -impl TryFrom for Commit { - type Error = Error; +tendermint_pb_modules! { + use super::Commit; + use crate::{ + block::commit_sig::CommitSig, + error::Error, + prelude::*, + }; + use pb::types::Commit as RawCommit; + + impl TryFrom for Commit { + type Error = Error; - fn try_from(value: RawCommit) -> Result { - let signatures: Result, Error> = value - .signatures - .into_iter() - .map(TryFrom::try_from) - .collect(); - Ok(Self { - height: value.height.try_into()?, - round: value.round.try_into()?, - block_id: value - .block_id - .ok_or_else(|| Error::invalid_block("missing block id".to_string()))? - .try_into()?, // gogoproto.nullable = false - signatures: signatures?, - }) + fn try_from(value: RawCommit) -> Result { + let signatures: Result, Error> = value + .signatures + .into_iter() + .map(TryFrom::try_from) + .collect(); + Ok(Self { + height: value.height.try_into()?, + round: value.round.try_into()?, + block_id: value + .block_id + .ok_or_else(|| Error::invalid_block("missing block id".to_string()))? + .try_into()?, // gogoproto.nullable = false + signatures: signatures?, + }) + } } -} -impl From for RawCommit { - fn from(value: Commit) -> Self { - RawCommit { - height: value.height.into(), - round: value.round.into(), - block_id: Some(value.block_id.into()), - signatures: value.signatures.into_iter().map(Into::into).collect(), + impl From for RawCommit { + fn from(value: Commit) -> Self { + RawCommit { + height: value.height.into(), + round: value.round.into(), + block_id: Some(value.block_id.into()), + signatures: value.signatures.into_iter().map(Into::into).collect(), + } } } } diff --git a/tendermint/src/block/commit_sig.rs b/tendermint/src/block/commit_sig.rs index a462366db..39c71cc1c 100644 --- a/tendermint/src/block/commit_sig.rs +++ b/tendermint/src/block/commit_sig.rs @@ -1,11 +1,6 @@ //! CommitSig within Commit -use core::convert::{TryFrom, TryInto}; - -use num_traits::ToPrimitive; -use tendermint_proto::types::{BlockIdFlag, CommitSig as RawCommitSig}; - -use crate::{account, error::Error, prelude::*, Signature, Time}; +use crate::{account, prelude::*, Signature, Time}; /// CommitSig represents a signature of a validator. /// It's a part of the Commit and can be used to reconstruct the vote set given the validator set. @@ -63,105 +58,112 @@ impl CommitSig { } } -// Todo: https://github.com/informalsystems/tendermint-rs/issues/259 - CommitSig Timestamp can be zero time -// Todo: https://github.com/informalsystems/tendermint-rs/issues/260 - CommitSig validator address missing in Absent vote -impl TryFrom for CommitSig { - type Error = Error; - - fn try_from(value: RawCommitSig) -> Result { - if value.block_id_flag == BlockIdFlag::Absent.to_i32().unwrap() { - if value.timestamp.is_some() { - let timestamp = value.timestamp.unwrap(); - // 0001-01-01T00:00:00.000Z translates to EPOCH-62135596800 seconds - if timestamp.nanos != 0 || timestamp.seconds != -62135596800 { - return Err(Error::invalid_timestamp( - "absent commitsig has non-zero timestamp".to_string(), +tendermint_pb_modules! { + use super::CommitSig; + use crate::{error::Error, prelude::*, Signature}; + use num_traits::ToPrimitive; + use pb::types::{BlockIdFlag, CommitSig as RawCommitSig}; + + // Todo: https://github.com/informalsystems/tendermint-rs/issues/259 - CommitSig Timestamp can be zero time + // Todo: https://github.com/informalsystems/tendermint-rs/issues/260 - CommitSig validator address missing in Absent vote + impl TryFrom for CommitSig { + type Error = Error; + + fn try_from(value: RawCommitSig) -> Result { + if value.block_id_flag == BlockIdFlag::Absent.to_i32().unwrap() { + if value.timestamp.is_some() { + let timestamp = value.timestamp.unwrap(); + // 0001-01-01T00:00:00.000Z translates to EPOCH-62135596800 seconds + if timestamp.nanos != 0 || timestamp.seconds != -62135596800 { + return Err(Error::invalid_timestamp( + "absent commitsig has non-zero timestamp".to_string(), + )); + } + } + + if !value.signature.is_empty() { + return Err(Error::invalid_signature( + "expected empty signature for absent commitsig".to_string(), )); } - } - if !value.signature.is_empty() { - return Err(Error::invalid_signature( - "expected empty signature for absent commitsig".to_string(), - )); + return Ok(CommitSig::BlockIdFlagAbsent); } - return Ok(CommitSig::BlockIdFlagAbsent); - } - - if value.block_id_flag == BlockIdFlag::Commit.to_i32().unwrap() { - if value.signature.is_empty() { - return Err(Error::invalid_signature( - "expected non-empty signature for regular commitsig".to_string(), - )); - } + if value.block_id_flag == BlockIdFlag::Commit.to_i32().unwrap() { + if value.signature.is_empty() { + return Err(Error::invalid_signature( + "expected non-empty signature for regular commitsig".to_string(), + )); + } - if value.validator_address.is_empty() { - return Err(Error::invalid_validator_address()); - } + if value.validator_address.is_empty() { + return Err(Error::invalid_validator_address()); + } - let timestamp = value - .timestamp - .ok_or_else(Error::missing_timestamp)? - .try_into()?; + let timestamp = value + .timestamp + .ok_or_else(Error::missing_timestamp)? + .try_into()?; - return Ok(CommitSig::BlockIdFlagCommit { - validator_address: value.validator_address.try_into()?, - timestamp, - signature: Signature::new(value.signature)?, - }); - } - if value.block_id_flag == BlockIdFlag::Nil.to_i32().unwrap() { - if value.signature.is_empty() { - return Err(Error::invalid_signature( - "nil commitsig has no signature".to_string(), - )); + return Ok(CommitSig::BlockIdFlagCommit { + validator_address: value.validator_address.try_into()?, + timestamp, + signature: Signature::new(value.signature)?, + }); } - if value.validator_address.is_empty() { - return Err(Error::invalid_validator_address()); + if value.block_id_flag == BlockIdFlag::Nil.to_i32().unwrap() { + if value.signature.is_empty() { + return Err(Error::invalid_signature( + "nil commitsig has no signature".to_string(), + )); + } + if value.validator_address.is_empty() { + return Err(Error::invalid_validator_address()); + } + return Ok(CommitSig::BlockIdFlagNil { + validator_address: value.validator_address.try_into()?, + timestamp: value + .timestamp + .ok_or_else(Error::missing_timestamp)? + .try_into()?, + signature: Signature::new(value.signature)?, + }); } - return Ok(CommitSig::BlockIdFlagNil { - validator_address: value.validator_address.try_into()?, - timestamp: value - .timestamp - .ok_or_else(Error::missing_timestamp)? - .try_into()?, - signature: Signature::new(value.signature)?, - }); + Err(Error::block_id_flag()) } - Err(Error::block_id_flag()) } -} -impl From for RawCommitSig { - fn from(commit: CommitSig) -> RawCommitSig { - match commit { - CommitSig::BlockIdFlagAbsent => RawCommitSig { - block_id_flag: BlockIdFlag::Absent.to_i32().unwrap(), - validator_address: Vec::new(), - timestamp: None, - signature: Vec::new(), - }, - CommitSig::BlockIdFlagNil { - validator_address, - timestamp, - signature, - } => RawCommitSig { - block_id_flag: BlockIdFlag::Nil.to_i32().unwrap(), - validator_address: validator_address.into(), - timestamp: Some(timestamp.into()), - signature: signature.map(|s| s.to_bytes()).unwrap_or_default(), - }, - CommitSig::BlockIdFlagCommit { - validator_address, - timestamp, - signature, - } => RawCommitSig { - block_id_flag: BlockIdFlag::Commit.to_i32().unwrap(), - validator_address: validator_address.into(), - timestamp: Some(timestamp.into()), - signature: signature.map(|s| s.to_bytes()).unwrap_or_default(), - }, + impl From for RawCommitSig { + fn from(commit: CommitSig) -> RawCommitSig { + match commit { + CommitSig::BlockIdFlagAbsent => RawCommitSig { + block_id_flag: BlockIdFlag::Absent.to_i32().unwrap(), + validator_address: Vec::new(), + timestamp: None, + signature: Vec::new(), + }, + CommitSig::BlockIdFlagNil { + validator_address, + timestamp, + signature, + } => RawCommitSig { + block_id_flag: BlockIdFlag::Nil.to_i32().unwrap(), + validator_address: validator_address.into(), + timestamp: Some(timestamp.into()), + signature: signature.map(|s| s.to_bytes()).unwrap_or_default(), + }, + CommitSig::BlockIdFlagCommit { + validator_address, + timestamp, + signature, + } => RawCommitSig { + block_id_flag: BlockIdFlag::Commit.to_i32().unwrap(), + validator_address: validator_address.into(), + timestamp: Some(timestamp.into()), + signature: signature.map(|s| s.to_bytes()).unwrap_or_default(), + }, + } } } } diff --git a/tendermint/src/block/header.rs b/tendermint/src/block/header.rs index ad747134b..c3f5a20a5 100644 --- a/tendermint/src/block/header.rs +++ b/tendermint/src/block/header.rs @@ -1,18 +1,18 @@ //! Block headers -use core::convert::{TryFrom, TryInto}; - use serde::{Deserialize, Serialize}; -use tendermint_proto::{ - types::Header as RawHeader, version::Consensus as RawConsensusVersion, Protobuf, +use tendermint_proto::v0_37::{ + types::{BlockId as RawBlockId, Header as RawHeader}, + version::Consensus as RawConsensusVersion, }; +use tendermint_proto::Protobuf; use crate::{ account, block, chain, crypto::Sha256, merkle::{self, MerkleHash}, prelude::*, - AppHash, Error, Hash, Time, + AppHash, Hash, Time, }; /// Block `Header` values contain metadata about the block and about the @@ -66,106 +66,6 @@ pub struct Header { pub proposer_address: account::Id, } -impl Protobuf for Header {} - -impl TryFrom for Header { - type Error = Error; - - fn try_from(value: RawHeader) -> Result { - // If last block id is unfilled, it is considered nil by Go. - let last_block_id = value - .last_block_id - .map(TryInto::try_into) - .transpose()? - .filter(|l| l != &block::Id::default()); - let last_commit_hash = if value.last_commit_hash.is_empty() { - None - } else { - Some(value.last_commit_hash.try_into()?) - }; - let last_results_hash = if value.last_results_hash.is_empty() { - None - } else { - Some(value.last_results_hash.try_into()?) - }; - let height: block::Height = value.height.try_into()?; - - // Todo: fix domain logic - // if last_block_id.is_none() && height.value() != 1 { - // return Err(Kind::InvalidHeader.context("last_block_id is null on non-first - // height").into()); - //} - if last_block_id.is_some() && height.value() == 1 { - return Err(Error::invalid_first_header()); - } - // if last_commit_hash.is_none() && height.value() != 1 { - // return Err(Kind::InvalidHeader.context("last_commit_hash is null on non-first - // height").into()); - //} - // if height.value() == 1 && last_commit_hash.is_some() && - // last_commit_hash.as_ref().unwrap() != simple_hash_from_byte_vectors(Vec::new()) { - // return Err(Kind::InvalidFirstHeader.context("last_commit_hash is not empty Merkle tree - // on first height").into()); - //} - // if last_results_hash.is_none() && height.value() != 1 { - // return Err(Kind::InvalidHeader.context("last_results_hash is null on non-first - // height").into()); - //} - // if last_results_hash.is_some() && height.value() == 1 { - // return Err(Kind::InvalidFirstHeader.context("last_results_hash is not ull on first - // height").into()); - //} - Ok(Header { - version: value.version.ok_or_else(Error::missing_version)?.into(), - chain_id: value.chain_id.try_into()?, - height, - time: value - .time - .ok_or_else(Error::missing_timestamp)? - .try_into()?, - last_block_id, - last_commit_hash, - data_hash: if value.data_hash.is_empty() { - None - } else { - Some(value.data_hash.try_into()?) - }, - validators_hash: value.validators_hash.try_into()?, - next_validators_hash: value.next_validators_hash.try_into()?, - consensus_hash: value.consensus_hash.try_into()?, - app_hash: value.app_hash.try_into()?, - last_results_hash, - evidence_hash: if value.evidence_hash.is_empty() { - None - } else { - Some(value.evidence_hash.try_into()?) - }, // Todo: Is it illegal to have evidence of wrongdoing in the first block? - proposer_address: value.proposer_address.try_into()?, - }) - } -} - -impl From
for RawHeader { - fn from(value: Header) -> Self { - RawHeader { - version: Some(value.version.into()), - chain_id: value.chain_id.into(), - height: value.height.into(), - time: Some(value.time.into()), - last_block_id: value.last_block_id.map(Into::into), - last_commit_hash: value.last_commit_hash.unwrap_or_default().into(), - data_hash: value.data_hash.unwrap_or_default().into(), - validators_hash: value.validators_hash.into(), - next_validators_hash: value.next_validators_hash.into(), - consensus_hash: value.consensus_hash.into(), - app_hash: value.app_hash.into(), - last_results_hash: value.last_results_hash.unwrap_or_default().into(), - evidence_hash: value.evidence_hash.unwrap_or_default().into(), - proposer_address: value.proposer_address.into(), - } - } -} - impl Header { /// Computes the hash of this header. #[cfg(feature = "rust-crypto")] @@ -184,11 +84,11 @@ impl Header { // https://github.com/tendermint/tendermint/blob/134fe2896275bb926b49743c1e25493f6b24cc31/types/encoding_helper.go#L9:6 let fields_bytes = vec![ - self.version.encode_vec().unwrap(), + Protobuf::::encode_vec(&self.version).unwrap(), self.chain_id.encode_vec().unwrap(), self.height.encode_vec().unwrap(), self.time.encode_vec().unwrap(), - self.last_block_id.unwrap_or_default().encode_vec().unwrap(), + Protobuf::::encode_vec(&self.last_block_id.unwrap_or_default()).unwrap(), self.last_commit_hash .unwrap_or_default() .encode_vec() @@ -223,22 +123,135 @@ pub struct Version { pub app: u64, } -impl Protobuf for Version {} +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +tendermint_pb_modules! { + use super::{Header, Version}; + use crate::{block, Error}; + use pb::{ + types::Header as RawHeader, + version::Consensus as RawConsensusVersion, + }; + + impl Protobuf for Header {} + + impl TryFrom for Header { + type Error = Error; + + fn try_from(value: RawHeader) -> Result { + // If last block id is unfilled, it is considered nil by Go. + let last_block_id = value + .last_block_id + .map(TryInto::try_into) + .transpose()? + .filter(|l| l != &block::Id::default()); + let last_commit_hash = if value.last_commit_hash.is_empty() { + None + } else { + Some(value.last_commit_hash.try_into()?) + }; + let last_results_hash = if value.last_results_hash.is_empty() { + None + } else { + Some(value.last_results_hash.try_into()?) + }; + let height: block::Height = value.height.try_into()?; + + // Todo: fix domain logic + // if last_block_id.is_none() && height.value() != 1 { + // return Err(Kind::InvalidHeader.context("last_block_id is null on non-first + // height").into()); + //} + if last_block_id.is_some() && height.value() == 1 { + return Err(Error::invalid_first_header()); + } + // if last_commit_hash.is_none() && height.value() != 1 { + // return Err(Kind::InvalidHeader.context("last_commit_hash is null on non-first + // height").into()); + //} + // if height.value() == 1 && last_commit_hash.is_some() && + // last_commit_hash.as_ref().unwrap() != simple_hash_from_byte_vectors(Vec::new()) { + // return Err(Kind::InvalidFirstHeader.context("last_commit_hash is not empty Merkle tree + // on first height").into()); + //} + // if last_results_hash.is_none() && height.value() != 1 { + // return Err(Kind::InvalidHeader.context("last_results_hash is null on non-first + // height").into()); + //} + // if last_results_hash.is_some() && height.value() == 1 { + // return Err(Kind::InvalidFirstHeader.context("last_results_hash is not ull on first + // height").into()); + //} + Ok(Header { + version: value.version.ok_or_else(Error::missing_version)?.into(), + chain_id: value.chain_id.try_into()?, + height, + time: value + .time + .ok_or_else(Error::missing_timestamp)? + .try_into()?, + last_block_id, + last_commit_hash, + data_hash: if value.data_hash.is_empty() { + None + } else { + Some(value.data_hash.try_into()?) + }, + validators_hash: value.validators_hash.try_into()?, + next_validators_hash: value.next_validators_hash.try_into()?, + consensus_hash: value.consensus_hash.try_into()?, + app_hash: value.app_hash.try_into()?, + last_results_hash, + evidence_hash: if value.evidence_hash.is_empty() { + None + } else { + Some(value.evidence_hash.try_into()?) + }, // Todo: Is it illegal to have evidence of wrongdoing in the first block? + proposer_address: value.proposer_address.try_into()?, + }) + } + } + + impl From
for RawHeader { + fn from(value: Header) -> Self { + RawHeader { + version: Some(value.version.into()), + chain_id: value.chain_id.into(), + height: value.height.into(), + time: Some(value.time.into()), + last_block_id: value.last_block_id.map(Into::into), + last_commit_hash: value.last_commit_hash.unwrap_or_default().into(), + data_hash: value.data_hash.unwrap_or_default().into(), + validators_hash: value.validators_hash.into(), + next_validators_hash: value.next_validators_hash.into(), + consensus_hash: value.consensus_hash.into(), + app_hash: value.app_hash.into(), + last_results_hash: value.last_results_hash.unwrap_or_default().into(), + evidence_hash: value.evidence_hash.unwrap_or_default().into(), + proposer_address: value.proposer_address.into(), + } + } + } + + impl Protobuf for Version {} -impl From for Version { - fn from(value: RawConsensusVersion) -> Self { - Version { - block: value.block, - app: value.app, + impl From for Version { + fn from(value: RawConsensusVersion) -> Self { + Version { + block: value.block, + app: value.app, + } } } -} -impl From for RawConsensusVersion { - fn from(value: Version) -> Self { - RawConsensusVersion { - block: value.block, - app: value.app, + impl From for RawConsensusVersion { + fn from(value: Version) -> Self { + RawConsensusVersion { + block: value.block, + app: value.app, + } } } } diff --git a/tendermint/src/block/id.rs b/tendermint/src/block/id.rs index e42e50ca4..c88f7a1a4 100644 --- a/tendermint/src/block/id.rs +++ b/tendermint/src/block/id.rs @@ -1,17 +1,10 @@ use core::{ - convert::{TryFrom, TryInto}, fmt::{self, Display}, str::{self, FromStr}, }; use serde::{Deserialize, Serialize}; -use tendermint_proto::{ - types::{ - BlockId as RawBlockId, CanonicalBlockId as RawCanonicalBlockId, - PartSetHeader as RawPartSetHeader, - }, - Protobuf, -}; +use tendermint_proto::v0_37::types::BlockId as RawBlockId; use crate::{ block::parts::Header as PartSetHeader, @@ -62,68 +55,79 @@ pub struct Id { pub part_set_header: PartSetHeader, } -impl Protobuf for Id {} +tendermint_pb_modules! { + use pb::{ + types::{ + BlockId as RawBlockId, CanonicalBlockId as RawCanonicalBlockId, + PartSetHeader as RawPartSetHeader, + } + }; + use super::Id; + use crate::{prelude::*, Error}; + + impl Protobuf for Id {} -impl TryFrom for Id { - type Error = Error; + impl TryFrom for Id { + type Error = Error; - fn try_from(value: RawBlockId) -> Result { - if value.part_set_header.is_none() { - return Err(Error::invalid_part_set_header( - "part_set_header is None".to_string(), - )); + fn try_from(value: RawBlockId) -> Result { + if value.part_set_header.is_none() { + return Err(Error::invalid_part_set_header( + "part_set_header is None".to_string(), + )); + } + Ok(Self { + hash: value.hash.try_into()?, + part_set_header: value.part_set_header.unwrap().try_into()?, + }) } - Ok(Self { - hash: value.hash.try_into()?, - part_set_header: value.part_set_header.unwrap().try_into()?, - }) } -} -impl From for RawBlockId { - fn from(value: Id) -> Self { - // https://github.com/tendermint/tendermint/blob/1635d1339c73ae6a82e062cd2dc7191b029efa14/types/block.go#L1204 - // The Go implementation encodes a nil value into an empty struct. We try our best to - // anticipate an empty struct by using the default implementation which would otherwise be - // invalid. - if value == Id::default() { - RawBlockId { - hash: vec![], - part_set_header: Some(RawPartSetHeader { - total: 0, + impl From for RawBlockId { + fn from(value: Id) -> Self { + // https://github.com/tendermint/tendermint/blob/1635d1339c73ae6a82e062cd2dc7191b029efa14/types/block.go#L1204 + // The Go implementation encodes a nil value into an empty struct. We try our best to + // anticipate an empty struct by using the default implementation which would otherwise be + // invalid. + if value == Id::default() { + RawBlockId { hash: vec![], - }), - } - } else { - RawBlockId { - hash: value.hash.into(), - part_set_header: Some(value.part_set_header.into()), + part_set_header: Some(RawPartSetHeader { + total: 0, + hash: vec![], + }), + } + } else { + RawBlockId { + hash: value.hash.into(), + part_set_header: Some(value.part_set_header.into()), + } } } } -} -impl TryFrom for Id { - type Error = Error; + impl TryFrom for Id { + type Error = Error; - fn try_from(value: RawCanonicalBlockId) -> Result { - if value.part_set_header.is_none() { - return Err(Error::invalid_part_set_header( - "part_set_header is None".to_string(), - )); + fn try_from(value: RawCanonicalBlockId) -> Result { + if value.part_set_header.is_none() { + return Err(Error::invalid_part_set_header( + "part_set_header is None".to_string(), + )); + } + Ok(Self { + hash: value.hash.try_into()?, + part_set_header: value.part_set_header.unwrap().try_into()?, + }) } - Ok(Self { - hash: value.hash.try_into()?, - part_set_header: value.part_set_header.unwrap().try_into()?, - }) } -} -impl From for RawCanonicalBlockId { - fn from(value: Id) -> Self { - RawCanonicalBlockId { - hash: value.hash.as_bytes().to_vec(), - part_set_header: Some(value.part_set_header.into()), + impl From for RawCanonicalBlockId { + fn from(value: Id) -> Self { + RawCanonicalBlockId { + hash: value.hash.as_bytes().to_vec(), + part_set_header: Some(value.part_set_header.into()), + } } } } diff --git a/tendermint/src/block/meta.rs b/tendermint/src/block/meta.rs index 71c72f2da..4dbed2cdb 100644 --- a/tendermint/src/block/meta.rs +++ b/tendermint/src/block/meta.rs @@ -1,12 +1,10 @@ //! Block metadata -use core::convert::{TryFrom, TryInto}; - use serde::{Deserialize, Serialize}; -use tendermint_proto::types::BlockMeta as RawMeta; +use tendermint_proto::v0_37::types::BlockMeta as RawMeta; use super::{Header, Id}; -use crate::{error::Error, prelude::*}; +use crate::prelude::*; /// Block metadata - Todo: implement constructor and getters #[derive(Serialize, Deserialize, Clone, Debug)] @@ -25,32 +23,38 @@ pub struct Meta { pub num_txs: i64, } -impl TryFrom for Meta { - type Error = Error; - - fn try_from(value: RawMeta) -> Result { - Ok(Meta { - block_id: value - .block_id - .ok_or_else(|| Error::invalid_block("no block_id".to_string()))? - .try_into()?, - block_size: value.block_size, - header: value - .header - .ok_or_else(|| Error::invalid_block("no header".to_string()))? - .try_into()?, - num_txs: value.num_txs, - }) +tendermint_pb_modules! { + use super::Meta; + use crate::{error::Error, prelude::*}; + use pb::types::BlockMeta as RawMeta; + + impl TryFrom for Meta { + type Error = Error; + + fn try_from(value: RawMeta) -> Result { + Ok(Meta { + block_id: value + .block_id + .ok_or_else(|| Error::invalid_block("no block_id".to_string()))? + .try_into()?, + block_size: value.block_size, + header: value + .header + .ok_or_else(|| Error::invalid_block("no header".to_string()))? + .try_into()?, + num_txs: value.num_txs, + }) + } } -} -impl From for RawMeta { - fn from(value: Meta) -> Self { - RawMeta { - block_id: Some(value.block_id.into()), - block_size: value.block_size, - header: Some(value.header.into()), - num_txs: value.num_txs, + impl From for RawMeta { + fn from(value: Meta) -> Self { + RawMeta { + block_id: Some(value.block_id.into()), + block_size: value.block_size, + header: Some(value.header.into()), + num_txs: value.num_txs, + } } } } diff --git a/tendermint/src/block/parts.rs b/tendermint/src/block/parts.rs index 6ae906ec7..7635034f4 100644 --- a/tendermint/src/block/parts.rs +++ b/tendermint/src/block/parts.rs @@ -1,21 +1,9 @@ //! Block parts -use core::convert::TryFrom; - use serde::{Deserialize, Serialize}; -use tendermint_proto::{ - types::{ - CanonicalPartSetHeader as RawCanonicalPartSetHeader, PartSetHeader as RawPartSetHeader, - }, - Protobuf, -}; +use tendermint_proto::v0_37::types::PartSetHeader as RawPartSetHeader; -use crate::{ - error::Error, - hash::{Algorithm, SHA256_HASH_SIZE}, - prelude::*, - Hash, -}; +use crate::{error::Error, prelude::*, Hash}; /// Block parts header #[derive( @@ -31,50 +19,63 @@ pub struct Header { pub hash: Hash, } -impl Protobuf for Header {} +tendermint_pb_modules! { + use pb::types::{ + CanonicalPartSetHeader as RawCanonicalPartSetHeader, PartSetHeader as RawPartSetHeader, + }; + use crate::{ + error::Error, + hash::{Algorithm, SHA256_HASH_SIZE}, + prelude::*, + Hash, + }; + use super::Header; + + impl Protobuf for Header {} -impl TryFrom for Header { - type Error = Error; + impl TryFrom for Header { + type Error = Error; - fn try_from(value: RawPartSetHeader) -> Result { - if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE { - return Err(Error::invalid_hash_size()); + fn try_from(value: RawPartSetHeader) -> Result { + if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE { + return Err(Error::invalid_hash_size()); + } + Ok(Self { + total: value.total, + hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?, + }) } - Ok(Self { - total: value.total, - hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?, - }) } -} -impl From
for RawPartSetHeader { - fn from(value: Header) -> Self { - RawPartSetHeader { - total: value.total, - hash: value.hash.into(), + impl From
for RawPartSetHeader { + fn from(value: Header) -> Self { + RawPartSetHeader { + total: value.total, + hash: value.hash.into(), + } } } -} -impl TryFrom for Header { - type Error = Error; + impl TryFrom for Header { + type Error = Error; - fn try_from(value: RawCanonicalPartSetHeader) -> Result { - if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE { - return Err(Error::invalid_hash_size()); + fn try_from(value: RawCanonicalPartSetHeader) -> Result { + if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE { + return Err(Error::invalid_hash_size()); + } + Ok(Self { + total: value.total, + hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?, + }) } - Ok(Self { - total: value.total, - hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?, - }) } -} -impl From
for RawCanonicalPartSetHeader { - fn from(value: Header) -> Self { - RawCanonicalPartSetHeader { - total: value.total, - hash: value.hash.into(), + impl From
for RawCanonicalPartSetHeader { + fn from(value: Header) -> Self { + RawCanonicalPartSetHeader { + total: value.total, + hash: value.hash.into(), + } } } } diff --git a/tendermint/src/block/signed_header.rs b/tendermint/src/block/signed_header.rs index de2fc3ec2..4cd852920 100644 --- a/tendermint/src/block/signed_header.rs +++ b/tendermint/src/block/signed_header.rs @@ -1,10 +1,9 @@ //! SignedHeader contains commit and and block header. //! It is what the rpc endpoint /commit returns and hence can be used by a //! light client. -use core::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; -use tendermint_proto::{types::SignedHeader as RawSignedHeader, Protobuf}; +use tendermint_proto::v0_37::types::SignedHeader as RawSignedHeader; use crate::{block, Error}; @@ -19,32 +18,38 @@ pub struct SignedHeader { pub commit: block::Commit, } -impl TryFrom for SignedHeader { - type Error = Error; +tendermint_pb_modules! { + use super::SignedHeader; + use crate::Error; + use pb::types::SignedHeader as RawSignedHeader; - fn try_from(value: RawSignedHeader) -> Result { - let header = value - .header - .ok_or_else(Error::invalid_signed_header)? - .try_into()?; - let commit = value - .commit - .ok_or_else(Error::invalid_signed_header)? - .try_into()?; - Self::new(header, commit) // Additional checks + impl TryFrom for SignedHeader { + type Error = Error; + + fn try_from(value: RawSignedHeader) -> Result { + let header = value + .header + .ok_or_else(Error::invalid_signed_header)? + .try_into()?; + let commit = value + .commit + .ok_or_else(Error::invalid_signed_header)? + .try_into()?; + Self::new(header, commit) // Additional checks + } } -} -impl From for RawSignedHeader { - fn from(value: SignedHeader) -> Self { - RawSignedHeader { - header: Some(value.header.into()), - commit: Some(value.commit.into()), + impl From for RawSignedHeader { + fn from(value: SignedHeader) -> Self { + RawSignedHeader { + header: Some(value.header.into()), + commit: Some(value.commit.into()), + } } } -} -impl Protobuf for SignedHeader {} + impl Protobuf for SignedHeader {} +} impl SignedHeader { /// Constructor. diff --git a/tendermint/src/block/size.rs b/tendermint/src/block/size.rs index 093cd580d..52204eec5 100644 --- a/tendermint/src/block/size.rs +++ b/tendermint/src/block/size.rs @@ -1,11 +1,8 @@ //! Block size parameters -use core::convert::{TryFrom, TryInto}; - use serde::{Deserialize, Serialize}; -use tendermint_proto::{abci::BlockParams as RawAbciSize, types::BlockParams as RawSize, Protobuf}; -use crate::{error::Error, serializers}; +use crate::serializers; /// Block size parameters #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] @@ -25,62 +22,105 @@ pub struct Size { impl Size { /// The default value for the `time_iota_ms` parameter. - pub fn default_time_iota_ms() -> i64 { + pub const fn default_time_iota_ms() -> i64 { 1000 } } -impl Protobuf for Size {} +mod v0_34 { + use super::Size; + use crate::error::Error; + use tendermint_proto::v0_34::{ + abci::BlockParams as RawAbciSize, types::BlockParams as RawSize, + }; + use tendermint_proto::Protobuf; + + impl Protobuf for Size {} -impl TryFrom for Size { - type Error = Error; + impl TryFrom for Size { + type Error = Error; - fn try_from(value: RawSize) -> Result { - Ok(Self { - max_bytes: value - .max_bytes - .try_into() - .map_err(Error::integer_overflow)?, - max_gas: value.max_gas, - time_iota_ms: value.time_iota_ms, - }) + fn try_from(value: RawSize) -> Result { + Ok(Self { + max_bytes: value + .max_bytes + .try_into() + .map_err(Error::integer_overflow)?, + max_gas: value.max_gas, + time_iota_ms: value.time_iota_ms, + }) + } } -} -impl From for RawSize { - fn from(value: Size) -> Self { - // Todo: make the struct more robust so this can become infallible. - RawSize { - max_bytes: value.max_bytes as i64, - max_gas: value.max_gas, - time_iota_ms: value.time_iota_ms, + impl From for RawSize { + fn from(value: Size) -> Self { + // Todo: make the struct more robust so this can become infallible. + RawSize { + max_bytes: value.max_bytes as i64, + max_gas: value.max_gas, + time_iota_ms: value.time_iota_ms, + } } } -} -impl Protobuf for Size {} + impl Protobuf for Size {} -impl TryFrom for Size { - type Error = Error; + impl TryFrom for Size { + type Error = Error; - fn try_from(value: RawAbciSize) -> Result { - Ok(Self { - max_bytes: value - .max_bytes - .try_into() - .map_err(Error::integer_overflow)?, - max_gas: value.max_gas, - time_iota_ms: Self::default_time_iota_ms(), - }) + fn try_from(value: RawAbciSize) -> Result { + Ok(Self { + max_bytes: value + .max_bytes + .try_into() + .map_err(Error::integer_overflow)?, + max_gas: value.max_gas, + time_iota_ms: Self::default_time_iota_ms(), + }) + } + } + + impl From for RawAbciSize { + fn from(value: Size) -> Self { + // Todo: make the struct more robust so this can become infallible. + RawAbciSize { + max_bytes: value.max_bytes as i64, + max_gas: value.max_gas, + } + } } } -impl From for RawAbciSize { - fn from(value: Size) -> Self { - // Todo: make the struct more robust so this can become infallible. - RawAbciSize { - max_bytes: value.max_bytes as i64, - max_gas: value.max_gas, +mod v0_37 { + use super::Size; + use crate::error::Error; + use tendermint_proto::v0_37::types::BlockParams as RawSize; + use tendermint_proto::Protobuf; + + impl Protobuf for Size {} + + impl TryFrom for Size { + type Error = Error; + + fn try_from(value: RawSize) -> Result { + Ok(Self { + max_bytes: value + .max_bytes + .try_into() + .map_err(Error::integer_overflow)?, + max_gas: value.max_gas, + time_iota_ms: Size::default_time_iota_ms(), + }) + } + } + + impl From for RawSize { + fn from(value: Size) -> Self { + // Todo: make the struct more robust so this can become infallible. + RawSize { + max_bytes: value.max_bytes as i64, + max_gas: value.max_gas, + } } } } diff --git a/tendermint/src/consensus/params.rs b/tendermint/src/consensus/params.rs index e03031ec4..10361050a 100644 --- a/tendermint/src/consensus/params.rs +++ b/tendermint/src/consensus/params.rs @@ -1,18 +1,8 @@ //! Tendermint consensus parameters -use core::convert::{TryFrom, TryInto}; - use serde::{Deserialize, Serialize}; -use tendermint_proto::{ - abci::ConsensusParams as RawAbciParams, - types::{ - ConsensusParams as RawParams, ValidatorParams as RawValidatorParams, - VersionParams as RawVersionParams, - }, - Protobuf, -}; -use crate::{block, error::Error, evidence, prelude::*, public_key}; +use crate::{block, evidence, prelude::*, public_key}; /// All consensus-relevant parameters that can be adjusted by the ABCI app. /// @@ -31,76 +21,6 @@ pub struct Params { pub version: Option, } -impl Protobuf for Params {} - -impl TryFrom for Params { - type Error = Error; - - fn try_from(value: RawParams) -> Result { - Ok(Self { - block: value - .block - .ok_or_else(|| Error::invalid_block("missing block".to_string()))? - .try_into()?, - evidence: value - .evidence - .ok_or_else(Error::invalid_evidence)? - .try_into()?, - validator: value - .validator - .ok_or_else(Error::invalid_validator_params)? - .try_into()?, - version: value.version.map(TryFrom::try_from).transpose()?, - }) - } -} - -impl From for RawParams { - fn from(value: Params) -> Self { - RawParams { - block: Some(value.block.into()), - evidence: Some(value.evidence.into()), - validator: Some(value.validator.into()), - version: value.version.map(From::from), - } - } -} - -impl Protobuf for Params {} - -impl TryFrom for Params { - type Error = Error; - - fn try_from(value: RawAbciParams) -> Result { - Ok(Self { - block: value - .block - .ok_or_else(|| Error::invalid_block("missing block".to_string()))? - .try_into()?, - evidence: value - .evidence - .ok_or_else(Error::invalid_evidence)? - .try_into()?, - validator: value - .validator - .ok_or_else(Error::invalid_validator_params)? - .try_into()?, - version: value.version.map(TryFrom::try_from).transpose()?, - }) - } -} - -impl From for RawAbciParams { - fn from(value: Params) -> Self { - RawAbciParams { - block: Some(value.block.into()), - evidence: Some(value.evidence.into()), - validator: Some(value.validator.into()), - version: value.version.map(From::from), - } - } -} - /// ValidatorParams restrict the public key types validators can use. /// /// [Tendermint documentation](https://docs.tendermint.com/master/spec/core/data_structures.html#validatorparams) @@ -110,18 +30,20 @@ pub struct ValidatorParams { pub pub_key_types: Vec, } -impl Protobuf for ValidatorParams {} - -impl TryFrom for ValidatorParams { - type Error = Error; - - fn try_from(value: RawValidatorParams) -> Result { - Ok(Self { - pub_key_types: value.pub_key_types.iter().map(|f| key_type(f)).collect(), - }) - } +/// Version Parameters +/// +/// [Tendermint documentation](https://docs.tendermint.com/master/spec/core/data_structures.html#versionparams) +#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Default)] +pub struct VersionParams { + /// The ABCI application version. + #[serde(with = "crate::serializers::from_str")] + pub app: u64, } +// ============================================================================= +// Protobuf conversions +// ============================================================================= + // Todo: How are these key types created? fn key_type(s: &str) -> public_key::Algorithm { if s == "Ed25519" || s == "ed25519" { @@ -133,47 +55,222 @@ fn key_type(s: &str) -> public_key::Algorithm { public_key::Algorithm::Ed25519 // Todo: Shall we error out for invalid key types? } -impl From for RawValidatorParams { - fn from(value: ValidatorParams) -> Self { - RawValidatorParams { - pub_key_types: value - .pub_key_types - .into_iter() - .map(|k| match k { - public_key::Algorithm::Ed25519 => "ed25519".to_string(), - public_key::Algorithm::Secp256k1 => "secp256k1".to_string(), - }) - .collect(), +mod v0_34 { + use tendermint_proto::v0_34::{ + abci::ConsensusParams as RawAbciParams, + types::{ + ConsensusParams as RawParams, ValidatorParams as RawValidatorParams, + VersionParams as RawVersionParams, + }, + }; + use tendermint_proto::Protobuf; + + use super::{key_type, Params, ValidatorParams, VersionParams}; + use crate::{error::Error, prelude::*, public_key}; + + impl Protobuf for Params {} + + impl TryFrom for Params { + type Error = Error; + + fn try_from(value: RawParams) -> Result { + Ok(Self { + block: value + .block + .ok_or_else(|| Error::invalid_block("missing block".to_string()))? + .try_into()?, + evidence: value + .evidence + .ok_or_else(Error::invalid_evidence)? + .try_into()?, + validator: value + .validator + .ok_or_else(Error::invalid_validator_params)? + .try_into()?, + version: value.version.map(TryFrom::try_from).transpose()?, + }) } } -} -/// Version Parameters -/// -/// [Tendermint documentation](https://docs.tendermint.com/master/spec/core/data_structures.html#versionparams) -#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Default)] -pub struct VersionParams { - /// The ABCI application version. - #[serde(with = "crate::serializers::from_str")] - pub app_version: u64, -} + impl From for RawParams { + fn from(value: Params) -> Self { + RawParams { + block: Some(value.block.into()), + evidence: Some(value.evidence.into()), + validator: Some(value.validator.into()), + version: value.version.map(From::from), + } + } + } + + impl Protobuf for Params {} -impl Protobuf for VersionParams {} + impl TryFrom for Params { + type Error = Error; -impl TryFrom for VersionParams { - type Error = Error; + fn try_from(value: RawAbciParams) -> Result { + Ok(Self { + block: value + .block + .ok_or_else(|| Error::invalid_block("missing block".to_string()))? + .try_into()?, + evidence: value + .evidence + .ok_or_else(Error::invalid_evidence)? + .try_into()?, + validator: value + .validator + .ok_or_else(Error::invalid_validator_params)? + .try_into()?, + version: value.version.map(TryFrom::try_from).transpose()?, + }) + } + } + + impl From for RawAbciParams { + fn from(value: Params) -> Self { + RawAbciParams { + block: Some(value.block.into()), + evidence: Some(value.evidence.into()), + validator: Some(value.validator.into()), + version: value.version.map(From::from), + } + } + } + + impl Protobuf for ValidatorParams {} + + impl TryFrom for ValidatorParams { + type Error = Error; + + fn try_from(value: RawValidatorParams) -> Result { + Ok(Self { + pub_key_types: value.pub_key_types.iter().map(|f| key_type(f)).collect(), + }) + } + } + + impl From for RawValidatorParams { + fn from(value: ValidatorParams) -> Self { + RawValidatorParams { + pub_key_types: value + .pub_key_types + .into_iter() + .map(|k| match k { + public_key::Algorithm::Ed25519 => "ed25519".to_string(), + public_key::Algorithm::Secp256k1 => "secp256k1".to_string(), + }) + .collect(), + } + } + } + + impl Protobuf for VersionParams {} - fn try_from(value: RawVersionParams) -> Result { - Ok(Self { - app_version: value.app_version, - }) + impl TryFrom for VersionParams { + type Error = Error; + + fn try_from(value: RawVersionParams) -> Result { + Ok(Self { + app: value.app_version, + }) + } + } + + impl From for RawVersionParams { + fn from(value: VersionParams) -> Self { + RawVersionParams { + app_version: value.app, + } + } } } -impl From for RawVersionParams { - fn from(value: VersionParams) -> Self { - RawVersionParams { - app_version: value.app_version, +mod v0_37 { + use tendermint_proto::v0_37::types::{ + ConsensusParams as RawParams, ValidatorParams as RawValidatorParams, + VersionParams as RawVersionParams, + }; + use tendermint_proto::Protobuf; + + use super::{key_type, Params, ValidatorParams, VersionParams}; + use crate::{error::Error, prelude::*, public_key}; + + impl Protobuf for Params {} + + impl TryFrom for Params { + type Error = Error; + + fn try_from(value: RawParams) -> Result { + Ok(Self { + block: value + .block + .ok_or_else(|| Error::invalid_block("missing block".to_string()))? + .try_into()?, + evidence: value + .evidence + .ok_or_else(Error::invalid_evidence)? + .try_into()?, + validator: value + .validator + .ok_or_else(Error::invalid_validator_params)? + .try_into()?, + version: value.version.map(TryFrom::try_from).transpose()?, + }) + } + } + + impl From for RawParams { + fn from(value: Params) -> Self { + RawParams { + block: Some(value.block.into()), + evidence: Some(value.evidence.into()), + validator: Some(value.validator.into()), + version: value.version.map(From::from), + } + } + } + + impl Protobuf for ValidatorParams {} + + impl TryFrom for ValidatorParams { + type Error = Error; + + fn try_from(value: RawValidatorParams) -> Result { + Ok(Self { + pub_key_types: value.pub_key_types.iter().map(|f| key_type(f)).collect(), + }) + } + } + + impl From for RawValidatorParams { + fn from(value: ValidatorParams) -> Self { + RawValidatorParams { + pub_key_types: value + .pub_key_types + .into_iter() + .map(|k| match k { + public_key::Algorithm::Ed25519 => "ed25519".to_string(), + public_key::Algorithm::Secp256k1 => "secp256k1".to_string(), + }) + .collect(), + } + } + } + + impl Protobuf for VersionParams {} + + impl TryFrom for VersionParams { + type Error = Error; + + fn try_from(value: RawVersionParams) -> Result { + Ok(Self { app: value.app }) + } + } + + impl From for RawVersionParams { + fn from(value: VersionParams) -> Self { + RawVersionParams { app: value.app } } } } diff --git a/tendermint/src/error.rs b/tendermint/src/error.rs index 25bae2264..dbcb93862 100644 --- a/tendermint/src/error.rs +++ b/tendermint/src/error.rs @@ -188,6 +188,9 @@ define_error! { UnsupportedOfferSnapshotChunkResult |_| { format_args!("unsupported OfferSnapshotChunkResult type" ) }, + UnsupportedProcessProposalStatus + |_| { format_args!("unsupported ProcessProposal status value" ) }, + RawVotingPowerMismatch { raw: vote::Power, computed: vote::Power } |e| { format_args!("mismatch between raw voting ({0:?}) and computed one ({1:?})", e.raw, e.computed) }, diff --git a/tendermint/src/evidence.rs b/tendermint/src/evidence.rs index cf8d6b524..af735007a 100644 --- a/tendermint/src/evidence.rs +++ b/tendermint/src/evidence.rs @@ -6,20 +6,11 @@ use core::{ }; use serde::{Deserialize, Serialize}; -use tendermint_proto::{ - google::protobuf::Duration as RawDuration, - types::{ - evidence::{Sum as RawSum, Sum}, - DuplicateVoteEvidence as RawDuplicateVoteEvidence, Evidence as RawEvidence, - EvidenceList as RawEvidenceList, EvidenceParams as RawEvidenceParams, - }, - Protobuf, -}; +use tendermint_proto::google::protobuf::Duration as RawDuration; +use tendermint_proto::v0_37::types::Evidence as RawEvidence; +use tendermint_proto::Protobuf; -use crate::{ - block::signed_header::SignedHeader, error::Error, prelude::*, serializers, vote::Power, Time, - Vote, -}; +use crate::{error::Error, prelude::*, serializers, vote::Power, Time, Vote}; /// Evidence of malfeasance by validators (i.e. signing conflicting votes). /// encoded using an Amino prefix. There is currently only a single type of @@ -27,46 +18,16 @@ use crate::{ /// /// #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -//#[serde(tag = "type", content = "value")] #[serde(try_from = "RawEvidence", into = "RawEvidence")] // Used by RPC /broadcast_evidence endpoint -// To be fixed in 0.24 #[allow(clippy::large_enum_variant)] pub enum Evidence { /// Duplicate vote evidence - //#[serde(rename = "tendermint/DuplicateVoteEvidence")] DuplicateVote(DuplicateVoteEvidence), - /// Conflicting headers evidence - Todo: this is not implemented in protobuf, it's ignored now - //#[serde(rename = "tendermint/ConflictingHeadersEvidence")] - ConflictingHeaders(Box), - /// LightClient attack evidence - Todo: Implement details LightClientAttackEvidence, } -impl TryFrom for Evidence { - type Error = Error; - - fn try_from(value: RawEvidence) -> Result { - match value.sum.ok_or_else(Error::invalid_evidence)? { - Sum::DuplicateVoteEvidence(ev) => Ok(Evidence::DuplicateVote(ev.try_into()?)), - Sum::LightClientAttackEvidence(_ev) => Ok(Evidence::LightClientAttackEvidence), - } - } -} - -impl From for RawEvidence { - fn from(value: Evidence) -> Self { - match value { - Evidence::DuplicateVote(ev) => RawEvidence { - sum: Some(RawSum::DuplicateVoteEvidence(ev.into())), - }, - Evidence::ConflictingHeaders(_ev) => RawEvidence { sum: None }, // Todo: implement - Evidence::LightClientAttackEvidence => RawEvidence { sum: None }, // Todo: implement - } - } -} - /// Duplicate vote evidence #[derive(Clone, Debug, PartialEq, Eq)] pub struct DuplicateVoteEvidence { @@ -77,41 +38,6 @@ pub struct DuplicateVoteEvidence { pub timestamp: Time, } -impl TryFrom for DuplicateVoteEvidence { - type Error = Error; - - fn try_from(value: RawDuplicateVoteEvidence) -> Result { - Ok(Self { - vote_a: value - .vote_a - .ok_or_else(Error::missing_evidence)? - .try_into()?, - vote_b: value - .vote_b - .ok_or_else(Error::missing_evidence)? - .try_into()?, - total_voting_power: value.total_voting_power.try_into()?, - validator_power: value.validator_power.try_into()?, - timestamp: value - .timestamp - .ok_or_else(Error::missing_timestamp)? - .try_into()?, - }) - } -} - -impl From for RawDuplicateVoteEvidence { - fn from(value: DuplicateVoteEvidence) -> Self { - RawDuplicateVoteEvidence { - vote_a: Some(value.vote_a.into()), - vote_b: Some(value.vote_b.into()), - total_voting_power: value.total_voting_power.into(), - validator_power: value.total_voting_power.into(), - timestamp: Some(value.timestamp.into()), - } - } -} - impl DuplicateVoteEvidence { /// constructor pub fn new(vote_a: Vote, vote_b: Vote) -> Result { @@ -133,58 +59,11 @@ impl DuplicateVoteEvidence { } } -/// Conflicting headers evidence. -// Todo: This struct doesn't seem to have a protobuf definition. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ConflictingHeadersEvidence { - //#[serde(rename = "H1")] - pub h1: SignedHeader, - //#[serde(rename = "H2")] - pub h2: SignedHeader, -} - -impl ConflictingHeadersEvidence { - /// Create a new evidence of conflicting headers - pub fn new(h1: SignedHeader, h2: SignedHeader) -> Self { - Self { h1, h2 } - } -} - /// Evidence data is a wrapper for a list of `Evidence`. /// /// #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] -#[serde(try_from = "RawEvidenceList", into = "RawEvidenceList")] -pub struct Data { - evidence: Option>, -} - -impl TryFrom for Data { - type Error = Error; - fn try_from(value: RawEvidenceList) -> Result { - if value.evidence.is_empty() { - return Ok(Self { evidence: None }); - } - let evidence: Result, Error> = - value.evidence.into_iter().map(TryInto::try_into).collect(); - Ok(Self { - evidence: Some(evidence?), - }) - } -} - -impl From for RawEvidenceList { - fn from(value: Data) -> Self { - RawEvidenceList { - evidence: value - .evidence - .unwrap_or_default() - .into_iter() - .map(Into::into) - .collect(), - } - } -} +pub struct Data(Vec); impl Data { /// Create a new evidence data collection @@ -192,25 +71,23 @@ impl Data { where I: Into>, { - Data { - evidence: Some(into_evidence.into()), - } + Data(into_evidence.into()) } /// Convert this evidence data into a vector pub fn into_vec(self) -> Vec { - self.iter().cloned().collect() + self.0 } /// Iterate over the evidence data pub fn iter(&self) -> slice::Iter<'_, Evidence> { - self.as_ref().iter() + self.0.iter() } } impl AsRef<[Evidence]> for Data { fn as_ref(&self) -> &[Evidence] { - self.evidence.as_deref().unwrap_or(&[]) + &self.0 } } @@ -240,33 +117,125 @@ pub struct Params { pub max_bytes: i64, } -impl Protobuf for Params {} +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +tendermint_pb_modules! { + use pb::types::{ + evidence::Sum as RawSum, DuplicateVoteEvidence as RawDuplicateVoteEvidence, + Evidence as RawEvidence, EvidenceList as RawEvidenceList, + EvidenceParams as RawEvidenceParams, + }; + + use super::{Data, DuplicateVoteEvidence, Evidence, Params}; + use crate::{error::Error, prelude::*}; + + impl TryFrom for Evidence { + type Error = Error; + + fn try_from(message: RawEvidence) -> Result { + use RawSum::*; + match message.sum.ok_or_else(Error::invalid_evidence)? { + DuplicateVoteEvidence(ev) => Ok(Evidence::DuplicateVote(ev.try_into()?)), + LightClientAttackEvidence(_ev) => Ok(Evidence::LightClientAttackEvidence), + } + } + } -impl TryFrom for Params { - type Error = Error; + impl From for RawEvidence { + fn from(value: Evidence) -> Self { + let sum = match value { + Evidence::DuplicateVote(ev) => Some(RawSum::DuplicateVoteEvidence(ev.into())), + Evidence::LightClientAttackEvidence => None, + }; + RawEvidence { sum } + } + } - fn try_from(value: RawEvidenceParams) -> Result { - Ok(Self { - max_age_num_blocks: value - .max_age_num_blocks - .try_into() - .map_err(Error::negative_max_age_num)?, - max_age_duration: value - .max_age_duration - .ok_or_else(Error::missing_max_age_duration)? - .try_into()?, - max_bytes: value.max_bytes, - }) + impl TryFrom for DuplicateVoteEvidence { + type Error = Error; + + fn try_from(value: RawDuplicateVoteEvidence) -> Result { + Ok(Self { + vote_a: value + .vote_a + .ok_or_else(Error::missing_evidence)? + .try_into()?, + vote_b: value + .vote_b + .ok_or_else(Error::missing_evidence)? + .try_into()?, + total_voting_power: value.total_voting_power.try_into()?, + validator_power: value.validator_power.try_into()?, + timestamp: value + .timestamp + .ok_or_else(Error::missing_timestamp)? + .try_into()?, + }) + } } -} -impl From for RawEvidenceParams { - fn from(value: Params) -> Self { - Self { - // Todo: Implement proper domain types so this becomes infallible - max_age_num_blocks: value.max_age_num_blocks.try_into().unwrap(), - max_age_duration: Some(value.max_age_duration.into()), - max_bytes: value.max_bytes, + impl From for RawDuplicateVoteEvidence { + fn from(value: DuplicateVoteEvidence) -> Self { + RawDuplicateVoteEvidence { + vote_a: Some(value.vote_a.into()), + vote_b: Some(value.vote_b.into()), + total_voting_power: value.total_voting_power.into(), + validator_power: value.total_voting_power.into(), + timestamp: Some(value.timestamp.into()), + } + } + } + + impl TryFrom for Data { + type Error = Error; + fn try_from(value: RawEvidenceList) -> Result { + let evidence = value + .evidence + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?; + Ok(Self(evidence)) + } + } + + impl From for RawEvidenceList { + fn from(value: Data) -> Self { + RawEvidenceList { + evidence: value.0.into_iter().map(Into::into).collect(), + } + } + } + + impl Protobuf for Params {} + + impl TryFrom for Params { + type Error = Error; + + fn try_from(value: RawEvidenceParams) -> Result { + Ok(Self { + max_age_num_blocks: value + .max_age_num_blocks + .try_into() + .map_err(Error::negative_max_age_num)?, + max_age_duration: value + .max_age_duration + .ok_or_else(Error::missing_max_age_duration)? + .try_into()?, + max_bytes: value.max_bytes, + }) + } + } + + impl From for RawEvidenceParams { + fn from(value: Params) -> Self { + Self { + // Todo: Implement proper domain types so this becomes infallible + max_age_num_blocks: value.max_age_num_blocks.try_into().unwrap(), + max_age_duration: Some(value.max_age_duration.into()), + max_bytes: value.max_bytes, + } } } } diff --git a/tendermint/src/hash.rs b/tendermint/src/hash.rs index 9e2a940fa..799dfa579 100644 --- a/tendermint/src/hash.rs +++ b/tendermint/src/hash.rs @@ -234,7 +234,7 @@ impl TryFrom for AppHash { type Error = Error; fn try_from(value: Bytes) -> Result { - Ok(AppHash(value.into())) + Ok(AppHash(value.to_vec())) } } impl From for Bytes { diff --git a/tendermint/src/lib.rs b/tendermint/src/lib.rs index ad70ff2ec..edc358010 100644 --- a/tendermint/src/lib.rs +++ b/tendermint/src/lib.rs @@ -24,6 +24,8 @@ extern crate alloc; extern crate std; #[macro_use] +mod proto_macros; + pub mod error; pub mod abci; @@ -41,6 +43,7 @@ mod moniker; pub mod node; mod prelude; pub mod private_key; +pub mod privval; pub mod proposal; pub mod public_key; pub mod serializers; @@ -53,6 +56,9 @@ pub mod validator; mod version; pub mod vote; +pub mod v0_34; +pub mod v0_37; + #[cfg(test)] mod test; diff --git a/tendermint/src/merkle/proof.rs b/tendermint/src/merkle/proof.rs index df5ad2bdd..903c1471c 100644 --- a/tendermint/src/merkle/proof.rs +++ b/tendermint/src/merkle/proof.rs @@ -1,13 +1,9 @@ //! Merkle proofs -use core::convert::TryFrom; use serde::{Deserialize, Serialize}; -use tendermint_proto::{ - crypto::{Proof as RawProof, ProofOp as RawProofOp, ProofOps as RawProofOps}, - Protobuf, -}; +use tendermint_proto::v0_37::crypto::Proof as RawProof; -use crate::{prelude::*, serializers, Error, Hash}; +use crate::{prelude::*, serializers, Hash}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "RawProof", into = "RawProof")] @@ -47,86 +43,98 @@ pub struct ProofOp { pub data: Vec, } -impl Protobuf for Proof {} - -impl TryFrom for Proof { - type Error = Error; - - fn try_from(message: RawProof) -> Result { - Ok(Self { - total: message - .total - .try_into() - .map_err(Error::negative_proof_total)?, - index: message - .index - .try_into() - .map_err(Error::negative_proof_index)?, - leaf_hash: message.leaf_hash.try_into()?, - aunts: message - .aunts - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - }) +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +tendermint_pb_modules! { + use super::{Proof, ProofOp, ProofOps}; + use crate::{prelude::*, Error}; + use pb::{ + crypto::{Proof as RawProof, ProofOp as RawProofOp, ProofOps as RawProofOps}, + }; + + impl Protobuf for Proof {} + + impl TryFrom for Proof { + type Error = Error; + + fn try_from(message: RawProof) -> Result { + Ok(Self { + total: message + .total + .try_into() + .map_err(Error::negative_proof_total)?, + index: message + .index + .try_into() + .map_err(Error::negative_proof_index)?, + leaf_hash: message.leaf_hash.try_into()?, + aunts: message + .aunts + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } } -} -impl From for RawProof { - fn from(value: Proof) -> Self { - Self { - total: value - .total - .try_into() - .expect("number of items is too large"), - index: value.index.try_into().expect("index is too large"), - leaf_hash: value.leaf_hash.into(), - aunts: value.aunts.into_iter().map(Into::into).collect(), + impl From for RawProof { + fn from(value: Proof) -> Self { + Self { + total: value + .total + .try_into() + .expect("number of items is too large"), + index: value.index.try_into().expect("index is too large"), + leaf_hash: value.leaf_hash.into(), + aunts: value.aunts.into_iter().map(Into::into).collect(), + } } } -} -impl Protobuf for ProofOp {} + impl Protobuf for ProofOp {} -impl TryFrom for ProofOp { - type Error = Error; + impl TryFrom for ProofOp { + type Error = Error; - fn try_from(value: RawProofOp) -> Result { - Ok(Self { - field_type: value.r#type, - key: value.key, - data: value.data, - }) + fn try_from(value: RawProofOp) -> Result { + Ok(Self { + field_type: value.r#type, + key: value.key, + data: value.data, + }) + } } -} -impl From for RawProofOp { - fn from(value: ProofOp) -> Self { - RawProofOp { - r#type: value.field_type, - key: value.key, - data: value.data, + impl From for RawProofOp { + fn from(value: ProofOp) -> Self { + RawProofOp { + r#type: value.field_type, + key: value.key, + data: value.data, + } } } -} -impl Protobuf for ProofOps {} + impl Protobuf for ProofOps {} -impl TryFrom for ProofOps { - type Error = Error; + impl TryFrom for ProofOps { + type Error = Error; - fn try_from(value: RawProofOps) -> Result { - let ops: Result, _> = value.ops.into_iter().map(ProofOp::try_from).collect(); + fn try_from(value: RawProofOps) -> Result { + let ops: Result, _> = value.ops.into_iter().map(ProofOp::try_from).collect(); - Ok(Self { ops: ops? }) + Ok(Self { ops: ops? }) + } } -} -impl From for RawProofOps { - fn from(value: ProofOps) -> Self { - let ops: Vec = value.ops.into_iter().map(RawProofOp::from).collect(); + impl From for RawProofOps { + fn from(value: ProofOps) -> Self { + let ops: Vec = value.ops.into_iter().map(RawProofOp::from).collect(); - RawProofOps { ops } + RawProofOps { ops } + } } } diff --git a/tendermint/src/privval.rs b/tendermint/src/privval.rs new file mode 100644 index 000000000..f4fa9af83 --- /dev/null +++ b/tendermint/src/privval.rs @@ -0,0 +1,40 @@ +//! Types used in the Privval protocol (Tendermint Core [ADR-063]) +//! +//! [ADR-063]: https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-063-privval-grpc.md + +use crate::prelude::*; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct RemoteSignerError { + pub code: i32, + pub description: String, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +tendermint_pb_modules! { + use super::RemoteSignerError; + use pb::privval::RemoteSignerError as RawRemoteSignerError; + + impl TryFrom for RemoteSignerError { + type Error = crate::Error; + + fn try_from(message: RawRemoteSignerError) -> Result { + Ok(Self { + code: message.code, + description: message.description, + }) + } + } + + impl From for RawRemoteSignerError { + fn from(value: RemoteSignerError) -> Self { + Self { + code: value.code, + description: value.description, + } + } + } +} diff --git a/tendermint/src/proposal.rs b/tendermint/src/proposal.rs index a5334529b..10c832b5a 100644 --- a/tendermint/src/proposal.rs +++ b/tendermint/src/proposal.rs @@ -4,19 +4,17 @@ mod canonical_proposal; mod msg_type; mod sign_proposal; -use core::convert::{TryFrom, TryInto}; - use bytes::BufMut; pub use msg_type::Type; pub use sign_proposal::{SignProposalRequest, SignedProposalResponse}; -use tendermint_proto::{types::Proposal as RawProposal, Error as ProtobufError, Protobuf}; +use tendermint_proto::v0_37::types::CanonicalProposal as RawCanonicalProposal; +use tendermint_proto::{Error as ProtobufError, Protobuf}; pub use self::canonical_proposal::CanonicalProposal; use crate::{ block::{Height, Id as BlockId, Round}, chain::Id as ChainId, consensus::State, - error::Error, prelude::*, Signature, Time, }; @@ -40,41 +38,47 @@ pub struct Proposal { pub signature: Option, } -impl Protobuf for Proposal {} - -impl TryFrom for Proposal { - type Error = Error; - - fn try_from(value: RawProposal) -> Result { - if value.pol_round < -1 { - return Err(Error::negative_pol_round()); +tendermint_pb_modules! { + use super::Proposal; + use crate::{Signature, Error, block::Round}; + use pb::types::Proposal as RawProposal; + + impl Protobuf for Proposal {} + + impl TryFrom for Proposal { + type Error = Error; + + fn try_from(value: RawProposal) -> Result { + if value.pol_round < -1 { + return Err(Error::negative_pol_round()); + } + let pol_round = match value.pol_round { + -1 => None, + n => Some(Round::try_from(n)?), + }; + Ok(Proposal { + msg_type: value.r#type.try_into()?, + height: value.height.try_into()?, + round: value.round.try_into()?, + pol_round, + block_id: value.block_id.map(TryInto::try_into).transpose()?, + timestamp: value.timestamp.map(|t| t.try_into()).transpose()?, + signature: Signature::new(value.signature)?, + }) } - let pol_round = match value.pol_round { - -1 => None, - n => Some(Round::try_from(n)?), - }; - Ok(Proposal { - msg_type: value.r#type.try_into()?, - height: value.height.try_into()?, - round: value.round.try_into()?, - pol_round, - block_id: value.block_id.map(TryInto::try_into).transpose()?, - timestamp: value.timestamp.map(|t| t.try_into()).transpose()?, - signature: Signature::new(value.signature)?, - }) } -} -impl From for RawProposal { - fn from(value: Proposal) -> Self { - RawProposal { - r#type: value.msg_type.into(), - height: value.height.into(), - round: value.round.into(), - pol_round: value.pol_round.map_or(-1, Into::into), - block_id: value.block_id.map(Into::into), - timestamp: value.timestamp.map(Into::into), - signature: value.signature.map(|s| s.to_bytes()).unwrap_or_default(), + impl From for RawProposal { + fn from(value: Proposal) -> Self { + RawProposal { + r#type: value.msg_type.into(), + height: value.height.into(), + round: value.round.into(), + pol_round: value.pol_round.map_or(-1, Into::into), + block_id: value.block_id.map(Into::into), + timestamp: value.timestamp.map(Into::into), + signature: value.signature.map(|s| s.to_bytes()).unwrap_or_default(), + } } } } @@ -89,13 +93,15 @@ impl Proposal { where B: BufMut, { - CanonicalProposal::new(self.clone(), chain_id).encode_length_delimited(sign_bytes)?; + let canonical = CanonicalProposal::new(self.clone(), chain_id); + Protobuf::::encode_length_delimited(&canonical, sign_bytes)?; Ok(true) } /// Create signable vector from Proposal. pub fn to_signable_vec(&self, chain_id: ChainId) -> Result, ProtobufError> { - CanonicalProposal::new(self.clone(), chain_id).encode_length_delimited_vec() + let canonical = CanonicalProposal::new(self.clone(), chain_id); + Protobuf::::encode_length_delimited_vec(&canonical) } /// Consensus state from this proposal - This doesn't seem to be used anywhere. @@ -115,9 +121,8 @@ impl Proposal { #[cfg(test)] mod tests { - use core::{convert::TryInto, str::FromStr}; + use core::str::FromStr; - use tendermint_proto::Protobuf; use time::macros::datetime; use crate::{ @@ -294,53 +299,57 @@ mod tests { assert_eq!(got, want) } - #[test] - fn test_deserialization() { - let dt = datetime!(2018-02-11 07:09:22.765 UTC); - let proposal = Proposal { - msg_type: Type::Proposal, - height: Height::from(12345_u32), - round: Round::from(23456_u16), - timestamp: Some(dt.try_into().unwrap()), - - pol_round: None, - block_id: Some(BlockId { - hash: Hash::from_hex_upper( - Algorithm::Sha256, - "DEADBEEFDEADBEEFBAFBAFBAFBAFBAFADEADBEEFDEADBEEFBAFBAFBAFBAFBAFA", - ) - .unwrap(), - part_set_header: Header::new( - 65535, - Hash::from_hex_upper( + tendermint_pb_modules! { + use super::*; + + #[test] + fn test_deserialization() { + let dt = datetime!(2018-02-11 07:09:22.765 UTC); + let proposal = Proposal { + msg_type: Type::Proposal, + height: Height::from(12345_u32), + round: Round::from(23456_u16), + timestamp: Some(dt.try_into().unwrap()), + + pol_round: None, + block_id: Some(BlockId { + hash: Hash::from_hex_upper( Algorithm::Sha256, - "0022446688AACCEE1133557799BBDDFF0022446688AACCEE1133557799BBDDFF", + "DEADBEEFDEADBEEFBAFBAFBAFBAFBAFADEADBEEFDEADBEEFBAFBAFBAFBAFBAFA", ) .unwrap(), - ) - .unwrap(), - }), - signature: Some(dummy_signature()), - }; - let want = SignProposalRequest { - proposal, - chain_id: ChainId::from_str("test_chain_id").unwrap(), - }; - - let data = vec![ - 10, 176, 1, 8, 32, 16, 185, 96, 24, 160, 183, 1, 32, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 1, 42, 74, 10, 32, 222, 173, 190, 239, 222, 173, 190, 239, 186, 251, 175, - 186, 251, 175, 186, 250, 222, 173, 190, 239, 222, 173, 190, 239, 186, 251, 175, 186, - 251, 175, 186, 250, 18, 38, 8, 255, 255, 3, 18, 32, 0, 34, 68, 102, 136, 170, 204, 238, - 17, 51, 85, 119, 153, 187, 221, 255, 0, 34, 68, 102, 136, 170, 204, 238, 17, 51, 85, - 119, 153, 187, 221, 255, 50, 12, 8, 162, 216, 255, 211, 5, 16, 192, 242, 227, 236, 2, - 58, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 13, 116, 101, 115, 116, 95, 99, 104, 97, 105, 110, 95, - 105, 100, - ]; - - let have = SignProposalRequest::decode_vec(&data).unwrap(); - assert_eq!(have, want); + part_set_header: Header::new( + 65535, + Hash::from_hex_upper( + Algorithm::Sha256, + "0022446688AACCEE1133557799BBDDFF0022446688AACCEE1133557799BBDDFF", + ) + .unwrap(), + ) + .unwrap(), + }), + signature: Some(dummy_signature()), + }; + let want = SignProposalRequest { + proposal, + chain_id: ChainId::from_str("test_chain_id").unwrap(), + }; + + let data = vec![ + 10, 176, 1, 8, 32, 16, 185, 96, 24, 160, 183, 1, 32, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 1, 42, 74, 10, 32, 222, 173, 190, 239, 222, 173, 190, 239, 186, 251, 175, + 186, 251, 175, 186, 250, 222, 173, 190, 239, 222, 173, 190, 239, 186, 251, 175, 186, + 251, 175, 186, 250, 18, 38, 8, 255, 255, 3, 18, 32, 0, 34, 68, 102, 136, 170, 204, 238, + 17, 51, 85, 119, 153, 187, 221, 255, 0, 34, 68, 102, 136, 170, 204, 238, 17, 51, 85, + 119, 153, 187, 221, 255, 50, 12, 8, 162, 216, 255, 211, 5, 16, 192, 242, 227, 236, 2, + 58, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 13, 116, 101, 115, 116, 95, 99, 104, 97, 105, 110, 95, + 105, 100, + ]; + + let have = >::decode_vec(&data).unwrap(); + assert_eq!(have, want); + } } } diff --git a/tendermint/src/proposal/canonical_proposal.rs b/tendermint/src/proposal/canonical_proposal.rs index d8346cadf..7113e9ca6 100644 --- a/tendermint/src/proposal/canonical_proposal.rs +++ b/tendermint/src/proposal/canonical_proposal.rs @@ -1,14 +1,9 @@ //! CanonicalProposal -use core::convert::{TryFrom, TryInto}; - -use tendermint_proto::{types::CanonicalProposal as RawCanonicalProposal, Protobuf}; - use super::Type; use crate::{ block::{Height, Id as BlockId, Round}, chain::Id as ChainId, - error::Error, prelude::*, Time, }; @@ -32,53 +27,64 @@ pub struct CanonicalProposal { pub chain_id: ChainId, } -impl Protobuf for CanonicalProposal {} +tendermint_pb_modules! { + use crate::{ + block::{Id as BlockId, Round}, + chain::Id as ChainId, + error::Error, + prelude::*, + }; + use super::CanonicalProposal; + use pb::types::CanonicalProposal as RawCanonicalProposal; -impl TryFrom for CanonicalProposal { - type Error = Error; + impl Protobuf for CanonicalProposal {} - fn try_from(value: RawCanonicalProposal) -> Result { - if value.pol_round < -1 { - return Err(Error::negative_pol_round()); + impl TryFrom for CanonicalProposal { + type Error = Error; + + fn try_from(value: RawCanonicalProposal) -> Result { + if value.pol_round < -1 { + return Err(Error::negative_pol_round()); + } + let round = Round::try_from(i32::try_from(value.round).map_err(Error::integer_overflow)?)?; + let pol_round = match value.pol_round { + -1 => None, + n => Some(Round::try_from( + i32::try_from(n).map_err(Error::integer_overflow)?, + )?), + }; + // If the Hash is empty in BlockId, the BlockId should be empty. + // See: https://github.com/informalsystems/tendermint-rs/issues/663 + let block_id = value.block_id.filter(|i| !i.hash.is_empty()); + Ok(CanonicalProposal { + msg_type: value.r#type.try_into()?, + height: value.height.try_into()?, + round, + pol_round, + block_id: block_id.map(TryInto::try_into).transpose()?, + timestamp: value.timestamp.map(|t| t.try_into()).transpose()?, + chain_id: ChainId::try_from(value.chain_id).unwrap(), + }) } - let round = Round::try_from(i32::try_from(value.round).map_err(Error::integer_overflow)?)?; - let pol_round = match value.pol_round { - -1 => None, - n => Some(Round::try_from( - i32::try_from(n).map_err(Error::integer_overflow)?, - )?), - }; - // If the Hash is empty in BlockId, the BlockId should be empty. - // See: https://github.com/informalsystems/tendermint-rs/issues/663 - let block_id = value.block_id.filter(|i| !i.hash.is_empty()); - Ok(CanonicalProposal { - msg_type: value.r#type.try_into()?, - height: value.height.try_into()?, - round, - pol_round, - block_id: block_id.map(TryInto::try_into).transpose()?, - timestamp: value.timestamp.map(|t| t.try_into()).transpose()?, - chain_id: ChainId::try_from(value.chain_id).unwrap(), - }) } -} -impl From for RawCanonicalProposal { - fn from(value: CanonicalProposal) -> Self { - // If the Hash is empty in BlockId, the BlockId should be empty. - // See: https://github.com/informalsystems/tendermint-rs/issues/663 - let block_id = value.block_id.filter(|i| i != &BlockId::default()); - RawCanonicalProposal { - r#type: value.msg_type.into(), - height: value.height.into(), - round: i32::from(value.round) as i64, - pol_round: match value.pol_round { - None => -1, - Some(p) => i32::from(p) as i64, - }, - block_id: block_id.map(Into::into), - timestamp: value.timestamp.map(Into::into), - chain_id: value.chain_id.as_str().to_string(), + impl From for RawCanonicalProposal { + fn from(value: CanonicalProposal) -> Self { + // If the Hash is empty in BlockId, the BlockId should be empty. + // See: https://github.com/informalsystems/tendermint-rs/issues/663 + let block_id = value.block_id.filter(|i| i != &BlockId::default()); + RawCanonicalProposal { + r#type: value.msg_type.into(), + height: value.height.into(), + round: i32::from(value.round) as i64, + pol_round: match value.pol_round { + None => -1, + Some(p) => i32::from(p) as i64, + }, + block_id: block_id.map(Into::into), + timestamp: value.timestamp.map(Into::into), + chain_id: value.chain_id.as_str().to_string(), + } } } } @@ -100,42 +106,42 @@ impl CanonicalProposal { #[cfg(test)] mod tests { - use core::convert::TryFrom; - - use tendermint_proto::types::{ - CanonicalBlockId as RawCanonicalBlockId, - CanonicalPartSetHeader as RawCanonicalPartSetHeader, - CanonicalProposal as RawCanonicalProposal, - }; + tendermint_pb_modules! { + use pb::types::{ + CanonicalBlockId as RawCanonicalBlockId, + CanonicalPartSetHeader as RawCanonicalPartSetHeader, + CanonicalProposal as RawCanonicalProposal, + }; - use crate::{ - prelude::*, - proposal::{canonical_proposal::CanonicalProposal, Type}, - }; + use crate::{ + prelude::*, + proposal::{canonical_proposal::CanonicalProposal, Type}, + }; - #[test] - fn canonical_proposal_domain_checks() { - // RawCanonicalProposal with edge cases to test domain knowledge - // pol_round = -1 should decode to None - // block_id with empty hash should decode to None - let proto_cp = RawCanonicalProposal { - r#type: 32, - height: 2, - round: 4, - pol_round: -1, - block_id: Some(RawCanonicalBlockId { - hash: vec![], - part_set_header: Some(RawCanonicalPartSetHeader { - total: 1, - hash: vec![1], + #[test] + fn canonical_proposal_domain_checks() { + // RawCanonicalProposal with edge cases to test domain knowledge + // pol_round = -1 should decode to None + // block_id with empty hash should decode to None + let proto_cp = RawCanonicalProposal { + r#type: 32, + height: 2, + round: 4, + pol_round: -1, + block_id: Some(RawCanonicalBlockId { + hash: vec![], + part_set_header: Some(RawCanonicalPartSetHeader { + total: 1, + hash: vec![1], + }), }), - }), - timestamp: None, - chain_id: "testchain".to_string(), - }; - let cp = CanonicalProposal::try_from(proto_cp).unwrap(); - assert_eq!(cp.msg_type, Type::Proposal); - assert!(cp.pol_round.is_none()); - assert!(cp.block_id.is_none()); + timestamp: None, + chain_id: "testchain".to_string(), + }; + let cp = CanonicalProposal::try_from(proto_cp).unwrap(); + assert_eq!(cp.msg_type, Type::Proposal); + assert!(cp.pol_round.is_none()); + assert!(cp.block_id.is_none()); + } } } diff --git a/tendermint/src/proposal/sign_proposal.rs b/tendermint/src/proposal/sign_proposal.rs index a78f8c813..fb4f0ff21 100644 --- a/tendermint/src/proposal/sign_proposal.rs +++ b/tendermint/src/proposal/sign_proposal.rs @@ -1,16 +1,8 @@ -use core::convert::{TryFrom, TryInto}; - use bytes::BufMut; -use tendermint_proto::{ - privval::{ - RemoteSignerError, SignProposalRequest as RawSignProposalRequest, - SignedProposalResponse as RawSignedProposalResponse, - }, - Error as ProtobufError, Protobuf, -}; +use tendermint_proto::Error as ProtobufError; use super::Proposal; -use crate::{chain::Id as ChainId, error::Error, prelude::*}; +use crate::{chain::Id as ChainId, prelude::*, privval::RemoteSignerError}; /// SignProposalRequest is a request to sign a proposal #[derive(Clone, PartialEq, Eq, Debug)] @@ -21,32 +13,6 @@ pub struct SignProposalRequest { pub chain_id: ChainId, } -impl Protobuf for SignProposalRequest {} -impl Protobuf for SignedProposalResponse {} - -impl TryFrom for SignProposalRequest { - type Error = Error; - - fn try_from(value: RawSignProposalRequest) -> Result { - if value.proposal.is_none() { - return Err(Error::no_proposal_found()); - } - Ok(SignProposalRequest { - proposal: Proposal::try_from(value.proposal.unwrap())?, - chain_id: ChainId::try_from(value.chain_id).unwrap(), - }) - } -} - -impl From for RawSignProposalRequest { - fn from(value: SignProposalRequest) -> Self { - RawSignProposalRequest { - proposal: Some(value.proposal.into()), - chain_id: value.chain_id.to_string(), - } - } -} - impl SignProposalRequest { /// Create signable bytes from Proposal. pub fn to_signable_bytes(&self, sign_bytes: &mut B) -> Result @@ -64,7 +30,7 @@ impl SignProposalRequest { } /// SignedProposalResponse is response containing a signed proposal or an error -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub struct SignedProposalResponse { /// Proposal pub proposal: Option, @@ -72,22 +38,61 @@ pub struct SignedProposalResponse { pub error: Option, } -impl TryFrom for SignedProposalResponse { - type Error = Error; +// ============================================================================= +// Protobuf conversions +// ============================================================================= - fn try_from(value: RawSignedProposalResponse) -> Result { - Ok(SignedProposalResponse { - proposal: value.proposal.map(TryInto::try_into).transpose()?, - error: value.error, - }) +tendermint_pb_modules! { + use pb::privval::{ + SignProposalRequest as RawSignProposalRequest, + SignedProposalResponse as RawSignedProposalResponse, + }; + use crate::{Error, Proposal, chain::Id as ChainId, prelude::*}; + use super::{SignProposalRequest, SignedProposalResponse}; + + impl Protobuf for SignProposalRequest {} + impl Protobuf for SignedProposalResponse {} + + impl TryFrom for SignProposalRequest { + type Error = Error; + + fn try_from(value: RawSignProposalRequest) -> Result { + if value.proposal.is_none() { + return Err(Error::no_proposal_found()); + } + Ok(SignProposalRequest { + proposal: Proposal::try_from(value.proposal.unwrap())?, + chain_id: ChainId::try_from(value.chain_id).unwrap(), + }) + } + } + + impl From for RawSignProposalRequest { + fn from(value: SignProposalRequest) -> Self { + RawSignProposalRequest { + proposal: Some(value.proposal.into()), + chain_id: value.chain_id.to_string(), + } + } + } + + impl TryFrom for SignedProposalResponse { + type Error = Error; + + fn try_from(value: RawSignedProposalResponse) -> Result { + Ok(SignedProposalResponse { + proposal: value.proposal.map(TryInto::try_into).transpose()?, + error: value.error.map(TryInto::try_into).transpose()?, + }) + } } -} -impl From for RawSignedProposalResponse { - fn from(value: SignedProposalResponse) -> Self { - RawSignedProposalResponse { - proposal: value.proposal.map(Into::into), - error: value.error, + impl From for RawSignedProposalResponse { + fn from(value: SignedProposalResponse) -> Self { + RawSignedProposalResponse { + proposal: value.proposal.map(Into::into), + error: value.error.map(Into::into), + } } } } diff --git a/tendermint/src/proto_macros.rs b/tendermint/src/proto_macros.rs new file mode 100644 index 000000000..49948a02b --- /dev/null +++ b/tendermint/src/proto_macros.rs @@ -0,0 +1,22 @@ +//! Macros to facilitate protobuf conversions + +macro_rules! tendermint_pb_modules { + { + $($contents:item)* + } => { + mod v0_34 { + use tendermint_proto::v0_34 as pb; + #[allow(unused_imports)] + use tendermint_proto::Protobuf; + + $($contents)* + } + mod v0_37 { + use tendermint_proto::v0_37 as pb; + #[allow(unused_imports)] + use tendermint_proto::Protobuf; + + $($contents)* + } + }; +} diff --git a/tendermint/src/public_key.rs b/tendermint/src/public_key.rs index 9f0289248..0efa72bec 100644 --- a/tendermint/src/public_key.rs +++ b/tendermint/src/public_key.rs @@ -14,10 +14,6 @@ use core::{cmp::Ordering, fmt, str::FromStr}; use serde::{de, ser, Deserialize, Deserializer, Serialize}; use serde_json::Value; use subtle_encoding::{base64, bech32, hex}; -use tendermint_proto::{ - crypto::{public_key::Sum, PublicKey as RawPublicKey}, - Protobuf, -}; pub use crate::crypto::ed25519::VerificationKey as Ed25519; use crate::{error::Error, prelude::*}; @@ -119,42 +115,48 @@ where .map_err(serde::de::Error::custom) } -impl Protobuf for PublicKey {} +tendermint_pb_modules! { + use super::{PublicKey, Ed25519}; + use pb::crypto::{PublicKey as RawPublicKey, public_key::Sum}; + use crate::{prelude::*, Error}; -impl TryFrom for PublicKey { - type Error = Error; + impl Protobuf for PublicKey {} - fn try_from(value: RawPublicKey) -> Result { - let sum = &value - .sum - .ok_or_else(|| Error::invalid_key("empty sum".to_string()))?; - if let Sum::Ed25519(b) = sum { - let key = Ed25519::try_from(&b[..])?; - return Ok(PublicKey::Ed25519(key)); - } - #[cfg(feature = "secp256k1")] - if let Sum::Secp256k1(b) = sum { - return Self::from_raw_secp256k1(b) - .ok_or_else(|| Error::invalid_key("malformed key".to_string())); + impl TryFrom for PublicKey { + type Error = Error; + + fn try_from(value: RawPublicKey) -> Result { + let sum = &value + .sum + .ok_or_else(|| Error::invalid_key("empty sum".to_string()))?; + if let Sum::Ed25519(b) = sum { + let key = Ed25519::try_from(&b[..])?; + return Ok(PublicKey::Ed25519(key)); + } + #[cfg(feature = "secp256k1")] + if let Sum::Secp256k1(b) = sum { + return Self::from_raw_secp256k1(b) + .ok_or_else(|| Error::invalid_key("malformed key".to_string())); + } + Err(Error::invalid_key("not an ed25519 key".to_string())) } - Err(Error::invalid_key("not an ed25519 key".to_string())) } -} -impl From for RawPublicKey { - fn from(value: PublicKey) -> Self { - match value { - PublicKey::Ed25519(ref pk) => RawPublicKey { - sum: Some(tendermint_proto::crypto::public_key::Sum::Ed25519( - pk.as_bytes().to_vec(), - )), - }, - #[cfg(feature = "secp256k1")] - PublicKey::Secp256k1(ref pk) => RawPublicKey { - sum: Some(tendermint_proto::crypto::public_key::Sum::Secp256k1( - pk.to_bytes().to_vec(), - )), - }, + impl From for RawPublicKey { + fn from(value: PublicKey) -> Self { + match value { + PublicKey::Ed25519(ref pk) => RawPublicKey { + sum: Some(Sum::Ed25519( + pk.as_bytes().to_vec(), + )), + }, + #[cfg(feature = "secp256k1")] + PublicKey::Secp256k1(ref pk) => RawPublicKey { + sum: Some(Sum::Secp256k1( + pk.to_bytes().to_vec(), + )), + }, + } } } } @@ -400,7 +402,6 @@ where #[cfg(test)] mod tests { use subtle_encoding::hex; - use tendermint_proto::Protobuf; use super::{PublicKey, TendermintKey}; use crate::{prelude::*, public_key::PubKeyResponse}; @@ -467,49 +468,57 @@ mod tests { assert_eq!(reserialized_json.as_str(), json_string); } - #[test] - fn test_ed25519_pubkey_msg() { - // test-vector generated from Go - // import ( - // "fmt" - // "github.com/tendermint/tendermint/proto/tendermint/crypto" - // "github.com/tendermint/tendermint/proto/tendermint/privval" - // ) - // - // func ed25519_key() { - // pkr := &privval.PubKeyResponse{ - // PubKey: &crypto.PublicKey{ - // Sum: &crypto.PublicKey_Ed25519{Ed25519: []byte{ - // 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, - // 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26, - // }, - // }, - // }, - // Error: nil, - // } - // pbpk, _ := pkr.Marshal() - // fmt.Printf("%#v\n", pbpk) - // - // } - let encoded = vec![ - 0xa, 0x22, 0xa, 0x20, 0xd7, 0x5a, 0x98, 0x1, 0x82, 0xb1, 0xa, 0xb7, 0xd5, 0x4b, 0xfe, - 0xd3, 0xc9, 0x64, 0x7, 0x3a, 0xe, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x2, - 0x1a, 0x68, 0xf7, 0x7, 0x51, 0x1a, - ]; - - let msg = PubKeyResponse { - pub_key: Some( - PublicKey::from_raw_ed25519(&[ - 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, - 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26, - ]) - .unwrap(), - ), - error: None, - }; - let got = msg.encode_vec().unwrap(); - - assert_eq!(got, encoded); - assert_eq!(PubKeyResponse::decode_vec(&encoded).unwrap(), msg); + tendermint_pb_modules! { + use super::*; + use pb::privval::PubKeyResponse as RawPubKeyResponse; + + #[test] + fn test_ed25519_pubkey_msg() { + // test-vector generated from Go + // import ( + // "fmt" + // "github.com/tendermint/tendermint/proto/tendermint/crypto" + // "github.com/tendermint/tendermint/proto/tendermint/privval" + // ) + // + // func ed25519_key() { + // pkr := &privval.PubKeyResponse{ + // PubKey: &crypto.PublicKey{ + // Sum: &crypto.PublicKey_Ed25519{Ed25519: []byte{ + // 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, + // 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26, + // }, + // }, + // }, + // Error: nil, + // } + // pbpk, _ := pkr.Marshal() + // fmt.Printf("%#v\n", pbpk) + // + // } + let encoded = vec![ + 0xa, 0x22, 0xa, 0x20, 0xd7, 0x5a, 0x98, 0x1, 0x82, 0xb1, 0xa, 0xb7, 0xd5, 0x4b, 0xfe, + 0xd3, 0xc9, 0x64, 0x7, 0x3a, 0xe, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x2, + 0x1a, 0x68, 0xf7, 0x7, 0x51, 0x1a, + ]; + + let msg = PubKeyResponse { + pub_key: Some( + PublicKey::from_raw_ed25519(&[ + 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, + 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26, + ]) + .unwrap(), + ), + error: None, + }; + let got = Protobuf::::encode_vec(&msg).unwrap(); + + assert_eq!(got, encoded); + let decoded = >::decode_vec( + &encoded + ).unwrap(); + assert_eq!(decoded, msg); + } } } diff --git a/tendermint/src/public_key/pub_key_request.rs b/tendermint/src/public_key/pub_key_request.rs index a83a163db..c6ee31eb9 100644 --- a/tendermint/src/public_key/pub_key_request.rs +++ b/tendermint/src/public_key/pub_key_request.rs @@ -1,8 +1,4 @@ -use core::convert::TryFrom; - -use tendermint_proto::{privval::PubKeyRequest as RawPubKeyRequest, Protobuf}; - -use crate::{chain::Id as ChainId, prelude::*, Error}; +use crate::{chain::Id as ChainId, prelude::*}; /// PubKeyRequest requests the consensus public key from the remote signer. #[derive(Clone, PartialEq, Eq, Debug)] @@ -11,63 +7,69 @@ pub struct PubKeyRequest { pub chain_id: ChainId, } -impl Protobuf for PubKeyRequest {} +tendermint_pb_modules! { + use super::PubKeyRequest; + use crate::{chain::Id as ChainId, prelude::*}; + use pb::privval::PubKeyRequest as RawPubKeyRequest; + + impl Protobuf for PubKeyRequest {} -impl TryFrom for PubKeyRequest { - type Error = Error; + impl TryFrom for PubKeyRequest { + type Error = crate::Error; - fn try_from(value: RawPubKeyRequest) -> Result { - Ok(PubKeyRequest { - chain_id: ChainId::try_from(value.chain_id)?, - }) + fn try_from(value: RawPubKeyRequest) -> Result { + Ok(PubKeyRequest { + chain_id: ChainId::try_from(value.chain_id)?, + }) + } } -} -impl From for RawPubKeyRequest { - fn from(value: PubKeyRequest) -> Self { - RawPubKeyRequest { - chain_id: value.chain_id.as_str().to_string(), + impl From for RawPubKeyRequest { + fn from(value: PubKeyRequest) -> Self { + RawPubKeyRequest { + chain_id: value.chain_id.as_str().to_string(), + } } } } #[cfg(test)] mod tests { - use core::str::FromStr; - - use tendermint_proto::Protobuf; - - use super::PubKeyRequest; - use crate::{chain::Id as ChainId, prelude::*}; + tendermint_pb_modules! { + use super::super::PubKeyRequest; + use pb::privval::PubKeyRequest as RawPubKeyRequest; + use crate::{chain::Id as ChainId, prelude::*}; + use core::str::FromStr; - #[test] - fn test_empty_pubkey_msg() { - // test-vector generated via the following go code: - // import ( - // "fmt" - // "github.com/tendermint/tendermint/proto/tendermint/privval" - // ) - // func ed25519_empty() { - // pkr := &privval.PubKeyRequest{ - // ChainId: "A", - // } - // pbpk, _ := pkr.Marshal() - // fmt.Printf("%#v\n", pbpk) - // - // } + #[test] + fn test_empty_pubkey_msg() { + // test-vector generated via the following go code: + // import ( + // "fmt" + // "github.com/tendermint/tendermint/proto/tendermint/privval" + // ) + // func ed25519_empty() { + // pkr := &privval.PubKeyRequest{ + // ChainId: "A", + // } + // pbpk, _ := pkr.Marshal() + // fmt.Printf("%#v\n", pbpk) + // + // } - let want: Vec = vec![10, 1, 65]; - let msg = PubKeyRequest { - chain_id: ChainId::from_str("A").unwrap(), - }; - let mut got = vec![]; - let _have = msg.encode(&mut got); + let want: Vec = vec![10, 1, 65]; + let msg = PubKeyRequest { + chain_id: ChainId::from_str("A").unwrap(), + }; + let mut got = vec![]; + Protobuf::::encode(&msg, &mut got).unwrap(); - assert_eq!(got, want); + assert_eq!(got, want); - match PubKeyRequest::decode(want.as_ref()) { - Ok(have) => assert_eq!(have, msg), - Err(err) => panic!("{}", err.to_string()), + match >::decode(want.as_ref()) { + Ok(have) => assert_eq!(have, msg), + Err(err) => panic!("{}", err.to_string()), + } } } } diff --git a/tendermint/src/public_key/pub_key_response.rs b/tendermint/src/public_key/pub_key_response.rs index bf337d848..e974912f1 100644 --- a/tendermint/src/public_key/pub_key_response.rs +++ b/tendermint/src/public_key/pub_key_response.rs @@ -1,14 +1,7 @@ -use core::convert::{TryFrom, TryInto}; - -use tendermint_proto::{ - privval::{PubKeyResponse as RawPubKeyResponse, RemoteSignerError}, - Protobuf, -}; - -use crate::{Error, PublicKey}; +use crate::{privval::RemoteSignerError, PublicKey}; /// PubKeyResponse -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] // Todo: either pub_key OR error is present pub struct PubKeyResponse { /// Public key @@ -18,26 +11,34 @@ pub struct PubKeyResponse { pub error: Option, } -impl Protobuf for PubKeyResponse {} +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +tendermint_pb_modules! { + use super::PubKeyResponse; + use pb::privval::PubKeyResponse as RawPubKeyResponse; + + impl Protobuf for PubKeyResponse {} -impl TryFrom for PubKeyResponse { - type Error = Error; + impl TryFrom for PubKeyResponse { + type Error = crate::Error; - fn try_from(value: RawPubKeyResponse) -> Result { - Ok(PubKeyResponse { - pub_key: value.pub_key.map(TryInto::try_into).transpose()?, - error: value.error, - }) + fn try_from(value: RawPubKeyResponse) -> Result { + Ok(PubKeyResponse { + pub_key: value.pub_key.map(TryInto::try_into).transpose()?, + error: value.error.map(TryInto::try_into).transpose()?, + }) + } } -} -impl From for RawPubKeyResponse { - fn from(value: PubKeyResponse) -> Self { - RawPubKeyResponse { - pub_key: value.pub_key.map(Into::into), - error: value.error, + impl From for RawPubKeyResponse { + fn from(value: PubKeyResponse) -> Self { + RawPubKeyResponse { + pub_key: value.pub_key.map(Into::into), + error: value.error.map(Into::into), + } } } } - // Todo: write unit test diff --git a/tendermint/src/tx/proof.rs b/tendermint/src/tx/proof.rs index 7d8abfa7a..98af54590 100644 --- a/tendermint/src/tx/proof.rs +++ b/tendermint/src/tx/proof.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use tendermint_proto::types::TxProof as RawTxProof; +use tendermint_proto::v0_37::types::TxProof as RawTxProof; use tendermint_proto::Protobuf; use crate::{merkle, prelude::*, Error, Hash}; diff --git a/tendermint/src/v0_34.rs b/tendermint/src/v0_34.rs new file mode 100644 index 000000000..c52eb0a4c --- /dev/null +++ b/tendermint/src/v0_34.rs @@ -0,0 +1 @@ +pub mod abci; diff --git a/tendermint/src/v0_34/abci.rs b/tendermint/src/v0_34/abci.rs new file mode 100644 index 000000000..601e534df --- /dev/null +++ b/tendermint/src/v0_34/abci.rs @@ -0,0 +1,5 @@ +pub mod request; +pub mod response; + +pub use request::Request; +pub use response::Response; diff --git a/tendermint/src/v0_34/abci/request.rs b/tendermint/src/v0_34/abci/request.rs new file mode 100644 index 000000000..6199750b8 --- /dev/null +++ b/tendermint/src/v0_34/abci/request.rs @@ -0,0 +1,225 @@ +use tendermint_proto::v0_34::abci as pb; +use tendermint_proto::Protobuf; + +use crate::abci::request::{ConsensusRequest, InfoRequest, MempoolRequest, SnapshotRequest}; +use crate::abci::MethodKind; +use crate::Error; + +pub use crate::abci::request::{ + ApplySnapshotChunk, BeginBlock, CheckTx, CheckTxKind, DeliverTx, Echo, EndBlock, Info, + InitChain, LoadSnapshotChunk, OfferSnapshot, Query, SetOption, +}; + +/// All possible ABCI requests. +#[allow(clippy::large_enum_variant)] +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Request { + #[doc = include_str!("../../abci/doc/request-echo.md")] + Echo(Echo), + #[doc = include_str!("../../abci/doc/request-flush.md")] + Flush, + #[doc = include_str!("../../abci/doc/request-info.md")] + Info(Info), + #[doc = include_str!("../../abci/doc/request-setoption.md")] + SetOption(SetOption), + #[doc = include_str!("../../abci/doc/request-initchain.md")] + InitChain(InitChain), + #[doc = include_str!("../../abci/doc/request-query.md")] + Query(Query), + #[doc = include_str!("../../abci/doc/request-beginblock.md")] + BeginBlock(BeginBlock), + #[doc = include_str!("../../abci/doc/request-checktx.md")] + CheckTx(CheckTx), + #[doc = include_str!("../../abci/doc/request-delivertx.md")] + DeliverTx(DeliverTx), + #[doc = include_str!("../../abci/doc/request-endblock.md")] + EndBlock(EndBlock), + #[doc = include_str!("../../abci/doc/request-commit.md")] + Commit, + #[doc = include_str!("../../abci/doc/request-listsnapshots.md")] + ListSnapshots, + #[doc = include_str!("../../abci/doc/request-offersnapshot.md")] + OfferSnapshot(OfferSnapshot), + #[doc = include_str!("../../abci/doc/request-loadsnapshotchunk.md")] + LoadSnapshotChunk(LoadSnapshotChunk), + #[doc = include_str!("../../abci/doc/request-applysnapshotchunk.md")] + ApplySnapshotChunk(ApplySnapshotChunk), +} + +impl Request { + /// Get the method kind for this request. + pub fn kind(&self) -> MethodKind { + use Request::*; + match self { + Flush => MethodKind::Flush, + InitChain(_) => MethodKind::Consensus, + BeginBlock(_) => MethodKind::Consensus, + DeliverTx(_) => MethodKind::Consensus, + EndBlock(_) => MethodKind::Consensus, + Commit => MethodKind::Consensus, + CheckTx(_) => MethodKind::Mempool, + ListSnapshots => MethodKind::Snapshot, + OfferSnapshot(_) => MethodKind::Snapshot, + LoadSnapshotChunk(_) => MethodKind::Snapshot, + ApplySnapshotChunk(_) => MethodKind::Snapshot, + Info(_) => MethodKind::Info, + Query(_) => MethodKind::Info, + Echo(_) => MethodKind::Info, + SetOption(_) => MethodKind::Info, + } + } +} + +impl From for Request { + fn from(req: ConsensusRequest) -> Self { + match req { + ConsensusRequest::InitChain(x) => Self::InitChain(x), + ConsensusRequest::PrepareProposal(_) => { + panic!("Cannot convert PrepareProposal into a v0.34 Request") + }, + ConsensusRequest::ProcessProposal(_) => { + panic!("Cannot convert ProcessProposal into a v0.34 Request") + }, + ConsensusRequest::BeginBlock(x) => Self::BeginBlock(x), + ConsensusRequest::DeliverTx(x) => Self::DeliverTx(x), + ConsensusRequest::EndBlock(x) => Self::EndBlock(x), + ConsensusRequest::Commit => Self::Commit, + } + } +} + +impl TryFrom for ConsensusRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::InitChain(x) => Ok(Self::InitChain(x)), + Request::BeginBlock(x) => Ok(Self::BeginBlock(x)), + Request::DeliverTx(x) => Ok(Self::DeliverTx(x)), + Request::EndBlock(x) => Ok(Self::EndBlock(x)), + Request::Commit => Ok(Self::Commit), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +impl From for Request { + fn from(req: MempoolRequest) -> Self { + match req { + MempoolRequest::CheckTx(x) => Self::CheckTx(x), + } + } +} + +impl TryFrom for MempoolRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::CheckTx(x) => Ok(Self::CheckTx(x)), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +impl From for Request { + fn from(req: InfoRequest) -> Self { + match req { + InfoRequest::Info(x) => Self::Info(x), + InfoRequest::Query(x) => Self::Query(x), + InfoRequest::Echo(x) => Self::Echo(x), + InfoRequest::SetOption(x) => Self::SetOption(x), + } + } +} + +impl TryFrom for InfoRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::Info(x) => Ok(Self::Info(x)), + Request::Query(x) => Ok(Self::Query(x)), + Request::Echo(x) => Ok(Self::Echo(x)), + Request::SetOption(x) => Ok(Self::SetOption(x)), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +impl From for Request { + fn from(req: SnapshotRequest) -> Self { + match req { + SnapshotRequest::ListSnapshots => Self::ListSnapshots, + SnapshotRequest::OfferSnapshot(x) => Self::OfferSnapshot(x), + SnapshotRequest::LoadSnapshotChunk(x) => Self::LoadSnapshotChunk(x), + SnapshotRequest::ApplySnapshotChunk(x) => Self::ApplySnapshotChunk(x), + } + } +} + +impl TryFrom for SnapshotRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::ListSnapshots => Ok(Self::ListSnapshots), + Request::OfferSnapshot(x) => Ok(Self::OfferSnapshot(x)), + Request::LoadSnapshotChunk(x) => Ok(Self::LoadSnapshotChunk(x)), + Request::ApplySnapshotChunk(x) => Ok(Self::ApplySnapshotChunk(x)), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +impl From for pb::Request { + fn from(request: Request) -> pb::Request { + use pb::request::Value; + let value = match request { + Request::Echo(x) => Some(Value::Echo(x.into())), + Request::Flush => Some(Value::Flush(Default::default())), + Request::Info(x) => Some(Value::Info(x.into())), + Request::SetOption(x) => Some(Value::SetOption(x.into())), + Request::InitChain(x) => Some(Value::InitChain(x.into())), + Request::Query(x) => Some(Value::Query(x.into())), + Request::BeginBlock(x) => Some(Value::BeginBlock(x.into())), + Request::CheckTx(x) => Some(Value::CheckTx(x.into())), + Request::DeliverTx(x) => Some(Value::DeliverTx(x.into())), + Request::EndBlock(x) => Some(Value::EndBlock(x.into())), + Request::Commit => Some(Value::Commit(Default::default())), + Request::ListSnapshots => Some(Value::ListSnapshots(Default::default())), + Request::OfferSnapshot(x) => Some(Value::OfferSnapshot(x.into())), + Request::LoadSnapshotChunk(x) => Some(Value::LoadSnapshotChunk(x.into())), + Request::ApplySnapshotChunk(x) => Some(Value::ApplySnapshotChunk(x.into())), + }; + pb::Request { value } + } +} + +impl TryFrom for Request { + type Error = Error; + + fn try_from(request: pb::Request) -> Result { + use pb::request::Value; + match request.value { + Some(Value::Echo(x)) => Ok(Request::Echo(x.try_into()?)), + Some(Value::Flush(pb::RequestFlush {})) => Ok(Request::Flush), + Some(Value::Info(x)) => Ok(Request::Info(x.try_into()?)), + Some(Value::SetOption(x)) => Ok(Request::SetOption(x.try_into()?)), + Some(Value::InitChain(x)) => Ok(Request::InitChain(x.try_into()?)), + Some(Value::Query(x)) => Ok(Request::Query(x.try_into()?)), + Some(Value::BeginBlock(x)) => Ok(Request::BeginBlock(x.try_into()?)), + Some(Value::CheckTx(x)) => Ok(Request::CheckTx(x.try_into()?)), + Some(Value::DeliverTx(x)) => Ok(Request::DeliverTx(x.try_into()?)), + Some(Value::EndBlock(x)) => Ok(Request::EndBlock(x.try_into()?)), + Some(Value::Commit(pb::RequestCommit {})) => Ok(Request::Commit), + Some(Value::ListSnapshots(pb::RequestListSnapshots {})) => Ok(Request::ListSnapshots), + Some(Value::OfferSnapshot(x)) => Ok(Request::OfferSnapshot(x.try_into()?)), + Some(Value::LoadSnapshotChunk(x)) => Ok(Request::LoadSnapshotChunk(x.try_into()?)), + Some(Value::ApplySnapshotChunk(x)) => Ok(Request::ApplySnapshotChunk(x.try_into()?)), + None => Err(crate::Error::missing_data()), + } + } +} + +impl Protobuf for Request {} diff --git a/tendermint/src/v0_34/abci/response.rs b/tendermint/src/v0_34/abci/response.rs new file mode 100644 index 000000000..3ab12b894 --- /dev/null +++ b/tendermint/src/v0_34/abci/response.rs @@ -0,0 +1,202 @@ +pub use crate::abci::response::{ + ApplySnapshotChunk, BeginBlock, CheckTx, Commit, DeliverTx, Echo, EndBlock, Exception, Info, + InitChain, ListSnapshots, LoadSnapshotChunk, OfferSnapshot, Query, SetOption, +}; +use crate::abci::response::{ConsensusResponse, InfoResponse, MempoolResponse, SnapshotResponse}; +use crate::Error; + +/// All possible ABCI responses for this protocol version. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Response { + #[doc = include_str!("../../abci/doc/response-exception.md")] + Exception(Exception), + #[doc = include_str!("../../abci/doc/response-echo.md")] + Echo(Echo), + #[doc = include_str!("../../abci/doc/response-flush.md")] + Flush, + #[doc = include_str!("../../abci/doc/response-info.md")] + Info(Info), + #[doc = include_str!("../../abci/doc/response-setoption.md")] + SetOption(SetOption), + #[doc = include_str!("../../abci/doc/response-initchain.md")] + InitChain(InitChain), + #[doc = include_str!("../../abci/doc/response-query.md")] + Query(Query), + #[doc = include_str!("../../abci/doc/response-beginblock.md")] + BeginBlock(BeginBlock), + #[doc = include_str!("../../abci/doc/response-checktx.md")] + CheckTx(CheckTx), + #[doc = include_str!("../../abci/doc/response-delivertx.md")] + DeliverTx(DeliverTx), + #[doc = include_str!("../../abci/doc/response-endblock.md")] + EndBlock(EndBlock), + #[doc = include_str!("../../abci/doc/response-commit.md")] + Commit(Commit), + #[doc = include_str!("../../abci/doc/response-listsnapshots.md")] + ListSnapshots(ListSnapshots), + #[doc = include_str!("../../abci/doc/response-offersnapshot.md")] + OfferSnapshot(OfferSnapshot), + #[doc = include_str!("../../abci/doc/response-loadsnapshotchunk.md")] + LoadSnapshotChunk(LoadSnapshotChunk), + #[doc = include_str!("../../abci/doc/response-applysnapshotchunk.md")] + ApplySnapshotChunk(ApplySnapshotChunk), +} + +impl From for Response { + fn from(req: ConsensusResponse) -> Self { + match req { + ConsensusResponse::InitChain(x) => Self::InitChain(x), + ConsensusResponse::PrepareProposal(_) => { + panic!("Cannot convert PrepareProposal into a v0.34 Response") + }, + ConsensusResponse::ProcessProposal(_) => { + panic!("Cannot convert ProcessProposal into a v0.34 Response") + }, + ConsensusResponse::BeginBlock(x) => Self::BeginBlock(x), + ConsensusResponse::DeliverTx(x) => Self::DeliverTx(x), + ConsensusResponse::EndBlock(x) => Self::EndBlock(x), + ConsensusResponse::Commit(x) => Self::Commit(x), + } + } +} + +impl TryFrom for ConsensusResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::InitChain(x) => Ok(Self::InitChain(x)), + Response::BeginBlock(x) => Ok(Self::BeginBlock(x)), + Response::DeliverTx(x) => Ok(Self::DeliverTx(x)), + Response::EndBlock(x) => Ok(Self::EndBlock(x)), + Response::Commit(x) => Ok(Self::Commit(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +impl From for Response { + fn from(req: MempoolResponse) -> Self { + match req { + MempoolResponse::CheckTx(x) => Self::CheckTx(x), + } + } +} + +impl TryFrom for MempoolResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::CheckTx(x) => Ok(Self::CheckTx(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +impl From for Response { + fn from(req: InfoResponse) -> Self { + match req { + InfoResponse::Echo(x) => Self::Echo(x), + InfoResponse::Info(x) => Self::Info(x), + InfoResponse::Query(x) => Self::Query(x), + InfoResponse::SetOption(x) => Self::SetOption(x), + } + } +} + +impl TryFrom for InfoResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::Echo(x) => Ok(Self::Echo(x)), + Response::Info(x) => Ok(Self::Info(x)), + Response::Query(x) => Ok(Self::Query(x)), + Response::SetOption(x) => Ok(Self::SetOption(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +impl From for Response { + fn from(req: SnapshotResponse) -> Self { + match req { + SnapshotResponse::ListSnapshots(x) => Self::ListSnapshots(x), + SnapshotResponse::OfferSnapshot(x) => Self::OfferSnapshot(x), + SnapshotResponse::LoadSnapshotChunk(x) => Self::LoadSnapshotChunk(x), + SnapshotResponse::ApplySnapshotChunk(x) => Self::ApplySnapshotChunk(x), + } + } +} + +impl TryFrom for SnapshotResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::ListSnapshots(x) => Ok(Self::ListSnapshots(x)), + Response::OfferSnapshot(x) => Ok(Self::OfferSnapshot(x)), + Response::LoadSnapshotChunk(x) => Ok(Self::LoadSnapshotChunk(x)), + Response::ApplySnapshotChunk(x) => Ok(Self::ApplySnapshotChunk(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use tendermint_proto::v0_34::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::Response { + fn from(response: Response) -> pb::Response { + use pb::response::Value; + let value = match response { + Response::Exception(x) => Some(Value::Exception(x.into())), + Response::Echo(x) => Some(Value::Echo(x.into())), + Response::Flush => Some(Value::Flush(Default::default())), + Response::Info(x) => Some(Value::Info(x.into())), + Response::SetOption(x) => Some(Value::SetOption(x.into())), + Response::InitChain(x) => Some(Value::InitChain(x.into())), + Response::Query(x) => Some(Value::Query(x.into())), + Response::BeginBlock(x) => Some(Value::BeginBlock(x.into())), + Response::CheckTx(x) => Some(Value::CheckTx(x.into())), + Response::DeliverTx(x) => Some(Value::DeliverTx(x.into())), + Response::EndBlock(x) => Some(Value::EndBlock(x.into())), + Response::Commit(x) => Some(Value::Commit(x.into())), + Response::ListSnapshots(x) => Some(Value::ListSnapshots(x.into())), + Response::OfferSnapshot(x) => Some(Value::OfferSnapshot(x.into())), + Response::LoadSnapshotChunk(x) => Some(Value::LoadSnapshotChunk(x.into())), + Response::ApplySnapshotChunk(x) => Some(Value::ApplySnapshotChunk(x.into())), + }; + pb::Response { value } + } +} + +impl TryFrom for Response { + type Error = Error; + + fn try_from(response: pb::Response) -> Result { + use pb::response::Value; + match response.value { + Some(Value::Exception(x)) => Ok(Response::Exception(x.try_into()?)), + Some(Value::Echo(x)) => Ok(Response::Echo(x.try_into()?)), + Some(Value::Flush(_)) => Ok(Response::Flush), + Some(Value::Info(x)) => Ok(Response::Info(x.try_into()?)), + Some(Value::SetOption(x)) => Ok(Response::SetOption(x.try_into()?)), + Some(Value::InitChain(x)) => Ok(Response::InitChain(x.try_into()?)), + Some(Value::Query(x)) => Ok(Response::Query(x.try_into()?)), + Some(Value::BeginBlock(x)) => Ok(Response::BeginBlock(x.try_into()?)), + Some(Value::CheckTx(x)) => Ok(Response::CheckTx(x.try_into()?)), + Some(Value::DeliverTx(x)) => Ok(Response::DeliverTx(x.try_into()?)), + Some(Value::EndBlock(x)) => Ok(Response::EndBlock(x.try_into()?)), + Some(Value::Commit(x)) => Ok(Response::Commit(x.try_into()?)), + Some(Value::ListSnapshots(x)) => Ok(Response::ListSnapshots(x.try_into()?)), + Some(Value::OfferSnapshot(x)) => Ok(Response::OfferSnapshot(x.try_into()?)), + Some(Value::LoadSnapshotChunk(x)) => Ok(Response::LoadSnapshotChunk(x.try_into()?)), + Some(Value::ApplySnapshotChunk(x)) => Ok(Response::ApplySnapshotChunk(x.try_into()?)), + None => Err(crate::Error::missing_data()), + } + } +} + +impl Protobuf for Response {} diff --git a/tendermint/src/v0_37.rs b/tendermint/src/v0_37.rs new file mode 100644 index 000000000..c52eb0a4c --- /dev/null +++ b/tendermint/src/v0_37.rs @@ -0,0 +1 @@ +pub mod abci; diff --git a/tendermint/src/v0_37/abci.rs b/tendermint/src/v0_37/abci.rs new file mode 100644 index 000000000..601e534df --- /dev/null +++ b/tendermint/src/v0_37/abci.rs @@ -0,0 +1,5 @@ +pub mod request; +pub mod response; + +pub use request::Request; +pub use response::Response; diff --git a/tendermint/src/v0_37/abci/request.rs b/tendermint/src/v0_37/abci/request.rs new file mode 100644 index 000000000..fce4d19c8 --- /dev/null +++ b/tendermint/src/v0_37/abci/request.rs @@ -0,0 +1,227 @@ +use tendermint_proto::v0_37::abci as pb; +use tendermint_proto::Protobuf; + +use crate::abci::request::{ConsensusRequest, InfoRequest, MempoolRequest, SnapshotRequest}; +use crate::abci::MethodKind; +use crate::Error; + +pub use crate::abci::request::{ + ApplySnapshotChunk, BeginBlock, CheckTx, CheckTxKind, DeliverTx, Echo, EndBlock, Info, + InitChain, LoadSnapshotChunk, OfferSnapshot, PrepareProposal, ProcessProposal, Query, +}; + +/// All possible ABCI requests. +#[allow(clippy::large_enum_variant)] +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Request { + #[doc = include_str!("../../abci/doc/request-echo.md")] + Echo(Echo), + #[doc = include_str!("../../abci/doc/request-flush.md")] + Flush, + #[doc = include_str!("../../abci/doc/request-info.md")] + Info(Info), + #[doc = include_str!("../../abci/doc/request-initchain.md")] + InitChain(InitChain), + #[doc = include_str!("../../abci/doc/request-query.md")] + Query(Query), + #[doc = include_str!("../../abci/doc/request-beginblock.md")] + BeginBlock(BeginBlock), + #[doc = include_str!("../../abci/doc/request-checktx.md")] + CheckTx(CheckTx), + #[doc = include_str!("../../abci/doc/request-delivertx.md")] + DeliverTx(DeliverTx), + #[doc = include_str!("../../abci/doc/request-endblock.md")] + EndBlock(EndBlock), + #[doc = include_str!("../../abci/doc/request-commit.md")] + Commit, + #[doc = include_str!("../../abci/doc/request-listsnapshots.md")] + ListSnapshots, + #[doc = include_str!("../../abci/doc/request-offersnapshot.md")] + OfferSnapshot(OfferSnapshot), + #[doc = include_str!("../../abci/doc/request-loadsnapshotchunk.md")] + LoadSnapshotChunk(LoadSnapshotChunk), + #[doc = include_str!("../../abci/doc/request-applysnapshotchunk.md")] + ApplySnapshotChunk(ApplySnapshotChunk), + #[doc = include_str!("../../abci/doc/request-prepareproposal.md")] + PrepareProposal(PrepareProposal), + #[doc = include_str!("../../abci/doc/request-processproposal.md")] + ProcessProposal(ProcessProposal), +} + +impl Request { + /// Get the method kind for this request. + pub fn kind(&self) -> MethodKind { + use Request::*; + match self { + Flush => MethodKind::Flush, + InitChain(_) => MethodKind::Consensus, + BeginBlock(_) => MethodKind::Consensus, + DeliverTx(_) => MethodKind::Consensus, + EndBlock(_) => MethodKind::Consensus, + Commit => MethodKind::Consensus, + PrepareProposal(_) => MethodKind::Consensus, + ProcessProposal(_) => MethodKind::Consensus, + CheckTx(_) => MethodKind::Mempool, + ListSnapshots => MethodKind::Snapshot, + OfferSnapshot(_) => MethodKind::Snapshot, + LoadSnapshotChunk(_) => MethodKind::Snapshot, + ApplySnapshotChunk(_) => MethodKind::Snapshot, + Info(_) => MethodKind::Info, + Query(_) => MethodKind::Info, + Echo(_) => MethodKind::Info, + } + } +} + +impl From for Request { + fn from(req: ConsensusRequest) -> Self { + match req { + ConsensusRequest::InitChain(x) => Self::InitChain(x), + ConsensusRequest::PrepareProposal(x) => Self::PrepareProposal(x), + ConsensusRequest::ProcessProposal(x) => Self::ProcessProposal(x), + ConsensusRequest::BeginBlock(x) => Self::BeginBlock(x), + ConsensusRequest::DeliverTx(x) => Self::DeliverTx(x), + ConsensusRequest::EndBlock(x) => Self::EndBlock(x), + ConsensusRequest::Commit => Self::Commit, + } + } +} + +impl TryFrom for ConsensusRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::InitChain(x) => Ok(Self::InitChain(x)), + Request::PrepareProposal(x) => Ok(Self::PrepareProposal(x)), + Request::ProcessProposal(x) => Ok(Self::ProcessProposal(x)), + Request::BeginBlock(x) => Ok(Self::BeginBlock(x)), + Request::DeliverTx(x) => Ok(Self::DeliverTx(x)), + Request::EndBlock(x) => Ok(Self::EndBlock(x)), + Request::Commit => Ok(Self::Commit), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +impl From for Request { + fn from(req: MempoolRequest) -> Self { + match req { + MempoolRequest::CheckTx(x) => Self::CheckTx(x), + } + } +} + +impl TryFrom for MempoolRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::CheckTx(x) => Ok(Self::CheckTx(x)), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +impl From for Request { + fn from(req: InfoRequest) -> Self { + match req { + InfoRequest::Info(x) => Self::Info(x), + InfoRequest::Query(x) => Self::Query(x), + InfoRequest::Echo(x) => Self::Echo(x), + InfoRequest::SetOption(_) => panic!("cannot be used with v0.37"), + } + } +} + +impl TryFrom for InfoRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::Info(x) => Ok(Self::Info(x)), + Request::Query(x) => Ok(Self::Query(x)), + Request::Echo(x) => Ok(Self::Echo(x)), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +impl From for Request { + fn from(req: SnapshotRequest) -> Self { + match req { + SnapshotRequest::ListSnapshots => Self::ListSnapshots, + SnapshotRequest::OfferSnapshot(x) => Self::OfferSnapshot(x), + SnapshotRequest::LoadSnapshotChunk(x) => Self::LoadSnapshotChunk(x), + SnapshotRequest::ApplySnapshotChunk(x) => Self::ApplySnapshotChunk(x), + } + } +} + +impl TryFrom for SnapshotRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::ListSnapshots => Ok(Self::ListSnapshots), + Request::OfferSnapshot(x) => Ok(Self::OfferSnapshot(x)), + Request::LoadSnapshotChunk(x) => Ok(Self::LoadSnapshotChunk(x)), + Request::ApplySnapshotChunk(x) => Ok(Self::ApplySnapshotChunk(x)), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +impl From for pb::Request { + fn from(request: Request) -> pb::Request { + use pb::request::Value; + let value = match request { + Request::Echo(x) => Some(Value::Echo(x.into())), + Request::Flush => Some(Value::Flush(Default::default())), + Request::Info(x) => Some(Value::Info(x.into())), + Request::InitChain(x) => Some(Value::InitChain(x.into())), + Request::Query(x) => Some(Value::Query(x.into())), + Request::BeginBlock(x) => Some(Value::BeginBlock(x.into())), + Request::CheckTx(x) => Some(Value::CheckTx(x.into())), + Request::DeliverTx(x) => Some(Value::DeliverTx(x.into())), + Request::EndBlock(x) => Some(Value::EndBlock(x.into())), + Request::Commit => Some(Value::Commit(Default::default())), + Request::ListSnapshots => Some(Value::ListSnapshots(Default::default())), + Request::OfferSnapshot(x) => Some(Value::OfferSnapshot(x.into())), + Request::LoadSnapshotChunk(x) => Some(Value::LoadSnapshotChunk(x.into())), + Request::ApplySnapshotChunk(x) => Some(Value::ApplySnapshotChunk(x.into())), + Request::PrepareProposal(x) => Some(Value::PrepareProposal(x.into())), + Request::ProcessProposal(x) => Some(Value::ProcessProposal(x.into())), + }; + pb::Request { value } + } +} + +impl TryFrom for Request { + type Error = Error; + + fn try_from(request: pb::Request) -> Result { + use pb::request::Value; + match request.value { + Some(Value::Echo(x)) => Ok(Request::Echo(x.try_into()?)), + Some(Value::Flush(pb::RequestFlush {})) => Ok(Request::Flush), + Some(Value::Info(x)) => Ok(Request::Info(x.try_into()?)), + Some(Value::InitChain(x)) => Ok(Request::InitChain(x.try_into()?)), + Some(Value::Query(x)) => Ok(Request::Query(x.try_into()?)), + Some(Value::BeginBlock(x)) => Ok(Request::BeginBlock(x.try_into()?)), + Some(Value::CheckTx(x)) => Ok(Request::CheckTx(x.try_into()?)), + Some(Value::DeliverTx(x)) => Ok(Request::DeliverTx(x.try_into()?)), + Some(Value::EndBlock(x)) => Ok(Request::EndBlock(x.try_into()?)), + Some(Value::Commit(pb::RequestCommit {})) => Ok(Request::Commit), + Some(Value::ListSnapshots(pb::RequestListSnapshots {})) => Ok(Request::ListSnapshots), + Some(Value::OfferSnapshot(x)) => Ok(Request::OfferSnapshot(x.try_into()?)), + Some(Value::LoadSnapshotChunk(x)) => Ok(Request::LoadSnapshotChunk(x.try_into()?)), + Some(Value::ApplySnapshotChunk(x)) => Ok(Request::ApplySnapshotChunk(x.try_into()?)), + Some(Value::PrepareProposal(x)) => Ok(Request::PrepareProposal(x.try_into()?)), + Some(Value::ProcessProposal(x)) => Ok(Request::ProcessProposal(x.try_into()?)), + None => Err(crate::Error::missing_data()), + } + } +} + +impl Protobuf for Request {} diff --git a/tendermint/src/v0_37/abci/response.rs b/tendermint/src/v0_37/abci/response.rs new file mode 100644 index 000000000..831f2783c --- /dev/null +++ b/tendermint/src/v0_37/abci/response.rs @@ -0,0 +1,204 @@ +pub use crate::abci::response::{ + ApplySnapshotChunk, BeginBlock, CheckTx, Commit, DeliverTx, Echo, EndBlock, Exception, Info, + InitChain, ListSnapshots, LoadSnapshotChunk, OfferSnapshot, PrepareProposal, ProcessProposal, + Query, +}; +use crate::abci::response::{ConsensusResponse, InfoResponse, MempoolResponse, SnapshotResponse}; +use crate::Error; + +/// All possible ABCI responses for this protocol version. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Response { + #[doc = include_str!("../../abci/doc/response-exception.md")] + Exception(Exception), + #[doc = include_str!("../../abci/doc/response-echo.md")] + Echo(Echo), + #[doc = include_str!("../../abci/doc/response-flush.md")] + Flush, + #[doc = include_str!("../../abci/doc/response-info.md")] + Info(Info), + #[doc = include_str!("../../abci/doc/response-initchain.md")] + InitChain(InitChain), + #[doc = include_str!("../../abci/doc/response-query.md")] + Query(Query), + #[doc = include_str!("../../abci/doc/response-beginblock.md")] + BeginBlock(BeginBlock), + #[doc = include_str!("../../abci/doc/response-checktx.md")] + CheckTx(CheckTx), + #[doc = include_str!("../../abci/doc/response-delivertx.md")] + DeliverTx(DeliverTx), + #[doc = include_str!("../../abci/doc/response-endblock.md")] + EndBlock(EndBlock), + #[doc = include_str!("../../abci/doc/response-commit.md")] + Commit(Commit), + #[doc = include_str!("../../abci/doc/response-listsnapshots.md")] + ListSnapshots(ListSnapshots), + #[doc = include_str!("../../abci/doc/response-offersnapshot.md")] + OfferSnapshot(OfferSnapshot), + #[doc = include_str!("../../abci/doc/response-loadsnapshotchunk.md")] + LoadSnapshotChunk(LoadSnapshotChunk), + #[doc = include_str!("../../abci/doc/response-applysnapshotchunk.md")] + ApplySnapshotChunk(ApplySnapshotChunk), + #[doc = include_str!("../../abci/doc/response-prepareproposal.md")] + PrepareProposal(PrepareProposal), + #[doc = include_str!("../../abci/doc/response-processproposal.md")] + ProcessProposal(ProcessProposal), +} + +impl From for Response { + fn from(req: ConsensusResponse) -> Self { + match req { + ConsensusResponse::InitChain(x) => Self::InitChain(x), + ConsensusResponse::PrepareProposal(x) => Self::PrepareProposal(x), + ConsensusResponse::ProcessProposal(x) => Self::ProcessProposal(x), + ConsensusResponse::BeginBlock(x) => Self::BeginBlock(x), + ConsensusResponse::DeliverTx(x) => Self::DeliverTx(x), + ConsensusResponse::EndBlock(x) => Self::EndBlock(x), + ConsensusResponse::Commit(x) => Self::Commit(x), + } + } +} + +impl TryFrom for ConsensusResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::InitChain(x) => Ok(Self::InitChain(x)), + Response::PrepareProposal(x) => Ok(Self::PrepareProposal(x)), + Response::ProcessProposal(x) => Ok(Self::ProcessProposal(x)), + Response::BeginBlock(x) => Ok(Self::BeginBlock(x)), + Response::DeliverTx(x) => Ok(Self::DeliverTx(x)), + Response::EndBlock(x) => Ok(Self::EndBlock(x)), + Response::Commit(x) => Ok(Self::Commit(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +impl From for Response { + fn from(req: MempoolResponse) -> Self { + match req { + MempoolResponse::CheckTx(x) => Self::CheckTx(x), + } + } +} + +impl TryFrom for MempoolResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::CheckTx(x) => Ok(Self::CheckTx(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +impl From for Response { + fn from(req: InfoResponse) -> Self { + match req { + InfoResponse::Echo(x) => Self::Echo(x), + InfoResponse::Info(x) => Self::Info(x), + InfoResponse::Query(x) => Self::Query(x), + InfoResponse::SetOption(_) => panic!("cannot be used with v0.37"), + } + } +} + +impl TryFrom for InfoResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::Echo(x) => Ok(Self::Echo(x)), + Response::Info(x) => Ok(Self::Info(x)), + Response::Query(x) => Ok(Self::Query(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +impl From for Response { + fn from(req: SnapshotResponse) -> Self { + match req { + SnapshotResponse::ListSnapshots(x) => Self::ListSnapshots(x), + SnapshotResponse::OfferSnapshot(x) => Self::OfferSnapshot(x), + SnapshotResponse::LoadSnapshotChunk(x) => Self::LoadSnapshotChunk(x), + SnapshotResponse::ApplySnapshotChunk(x) => Self::ApplySnapshotChunk(x), + } + } +} + +impl TryFrom for SnapshotResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::ListSnapshots(x) => Ok(Self::ListSnapshots(x)), + Response::OfferSnapshot(x) => Ok(Self::OfferSnapshot(x)), + Response::LoadSnapshotChunk(x) => Ok(Self::LoadSnapshotChunk(x)), + Response::ApplySnapshotChunk(x) => Ok(Self::ApplySnapshotChunk(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use tendermint_proto::v0_37::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::Response { + fn from(response: Response) -> pb::Response { + use pb::response::Value; + let value = match response { + Response::Exception(x) => Some(Value::Exception(x.into())), + Response::Echo(x) => Some(Value::Echo(x.into())), + Response::Flush => Some(Value::Flush(Default::default())), + Response::Info(x) => Some(Value::Info(x.into())), + Response::InitChain(x) => Some(Value::InitChain(x.into())), + Response::Query(x) => Some(Value::Query(x.into())), + Response::BeginBlock(x) => Some(Value::BeginBlock(x.into())), + Response::CheckTx(x) => Some(Value::CheckTx(x.into())), + Response::DeliverTx(x) => Some(Value::DeliverTx(x.into())), + Response::EndBlock(x) => Some(Value::EndBlock(x.into())), + Response::Commit(x) => Some(Value::Commit(x.into())), + Response::ListSnapshots(x) => Some(Value::ListSnapshots(x.into())), + Response::OfferSnapshot(x) => Some(Value::OfferSnapshot(x.into())), + Response::LoadSnapshotChunk(x) => Some(Value::LoadSnapshotChunk(x.into())), + Response::ApplySnapshotChunk(x) => Some(Value::ApplySnapshotChunk(x.into())), + Response::PrepareProposal(x) => Some(Value::PrepareProposal(x.into())), + Response::ProcessProposal(x) => Some(Value::ProcessProposal(x.into())), + }; + pb::Response { value } + } +} + +impl TryFrom for Response { + type Error = Error; + + fn try_from(response: pb::Response) -> Result { + use pb::response::Value; + match response.value { + Some(Value::Exception(x)) => Ok(Response::Exception(x.try_into()?)), + Some(Value::Echo(x)) => Ok(Response::Echo(x.try_into()?)), + Some(Value::Flush(_)) => Ok(Response::Flush), + Some(Value::Info(x)) => Ok(Response::Info(x.try_into()?)), + Some(Value::InitChain(x)) => Ok(Response::InitChain(x.try_into()?)), + Some(Value::Query(x)) => Ok(Response::Query(x.try_into()?)), + Some(Value::BeginBlock(x)) => Ok(Response::BeginBlock(x.try_into()?)), + Some(Value::CheckTx(x)) => Ok(Response::CheckTx(x.try_into()?)), + Some(Value::DeliverTx(x)) => Ok(Response::DeliverTx(x.try_into()?)), + Some(Value::EndBlock(x)) => Ok(Response::EndBlock(x.try_into()?)), + Some(Value::Commit(x)) => Ok(Response::Commit(x.try_into()?)), + Some(Value::ListSnapshots(x)) => Ok(Response::ListSnapshots(x.try_into()?)), + Some(Value::OfferSnapshot(x)) => Ok(Response::OfferSnapshot(x.try_into()?)), + Some(Value::LoadSnapshotChunk(x)) => Ok(Response::LoadSnapshotChunk(x.try_into()?)), + Some(Value::ApplySnapshotChunk(x)) => Ok(Response::ApplySnapshotChunk(x.try_into()?)), + Some(Value::PrepareProposal(x)) => Ok(Response::PrepareProposal(x.try_into()?)), + Some(Value::ProcessProposal(x)) => Ok(Response::ProcessProposal(x.try_into()?)), + None => Err(crate::Error::missing_data()), + } + } +} + +impl Protobuf for Response {} diff --git a/tendermint/src/validator.rs b/tendermint/src/validator.rs index 07022293f..8b232736e 100644 --- a/tendermint/src/validator.rs +++ b/tendermint/src/validator.rs @@ -1,16 +1,8 @@ //! Tendermint validators -use core::convert::{TryFrom, TryInto}; - use serde::{Deserialize, Serialize}; -use tendermint_proto::{ - abci::ValidatorUpdate as RawValidatorUpdate, - types::{ - SimpleValidator as RawSimpleValidator, Validator as RawValidator, - ValidatorSet as RawValidatorSet, - }, - Protobuf, -}; +use tendermint_proto::v0_37::types::SimpleValidator as RawSimpleValidator; +use tendermint_proto::Protobuf; use crate::{ account, @@ -31,44 +23,6 @@ pub struct Set { total_voting_power: vote::Power, } -impl Protobuf for Set {} - -impl TryFrom for Set { - type Error = Error; - - fn try_from(value: RawValidatorSet) -> Result { - let validators = value - .validators - .into_iter() - .map(TryInto::try_into) - .collect::, _>>()?; - - let proposer = value.proposer.map(TryInto::try_into).transpose()?; - let validator_set = Self::new(validators, proposer); - - // Ensure that the raw voting power matches the computed one - let raw_voting_power = value.total_voting_power.try_into()?; - if raw_voting_power != validator_set.total_voting_power() { - return Err(Error::raw_voting_power_mismatch( - raw_voting_power, - validator_set.total_voting_power(), - )); - } - - Ok(validator_set) - } -} - -impl From for RawValidatorSet { - fn from(value: Set) -> Self { - RawValidatorSet { - validators: value.validators.into_iter().map(Into::into).collect(), - proposer: value.proposer.map(Into::into), - total_voting_power: value.total_voting_power.into(), - } - } -} - impl Set { /// Constructor pub fn new(mut validators: Vec, proposer: Option) -> Set { @@ -184,34 +138,6 @@ pub struct Info { pub proposer_priority: ProposerPriority, } -impl TryFrom for Info { - type Error = Error; - - fn try_from(value: RawValidator) -> Result { - Ok(Info { - address: value.address.try_into()?, - pub_key: value - .pub_key - .ok_or_else(Error::missing_public_key)? - .try_into()?, - power: value.voting_power.try_into()?, - name: None, - proposer_priority: value.proposer_priority.into(), - }) - } -} - -impl From for RawValidator { - fn from(value: Info) -> Self { - RawValidator { - address: value.address.into(), - pub_key: Some(value.pub_key.into()), - voting_power: value.power.into(), - proposer_priority: value.proposer_priority.into(), - } - } -} - impl Info { /// Return the voting power of the validator. pub fn power(&self) -> u64 { @@ -246,50 +172,19 @@ impl Info { /// nor the proposer priority, as that changes with every block even if the validator set didn't. /// It contains only the pubkey and the voting power. /// TODO: currently only works for Ed25519 pubkeys -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq)] pub struct SimpleValidator { /// Public key - pub pub_key: Option, + pub pub_key: PublicKey, /// Voting power pub voting_power: vote::Power, } -impl Protobuf for SimpleValidator {} - -impl TryFrom for SimpleValidator { - type Error = Error; - - fn try_from(value: RawSimpleValidator) -> Result { - Ok(SimpleValidator { - pub_key: value.pub_key, - voting_power: value.voting_power.try_into()?, - }) - } -} - -impl From for RawSimpleValidator { - fn from(value: SimpleValidator) -> Self { - RawSimpleValidator { - pub_key: value.pub_key, - voting_power: value.voting_power.into(), - } - } -} - /// Info -> SimpleValidator impl From<&Info> for SimpleValidator { fn from(info: &Info) -> SimpleValidator { - let sum = match &info.pub_key { - PublicKey::Ed25519(pk) => Some(tendermint_proto::crypto::public_key::Sum::Ed25519( - pk.as_bytes().to_vec(), - )), - #[cfg(feature = "secp256k1")] - PublicKey::Secp256k1(pk) => Some(tendermint_proto::crypto::public_key::Sum::Secp256k1( - pk.to_bytes().to_vec(), - )), - }; SimpleValidator { - pub_key: Some(tendermint_proto::crypto::PublicKey { sum }), + pub_key: info.pub_key, voting_power: info.power, } } @@ -299,7 +194,7 @@ impl Info { /// Returns the bytes to be hashed into the Merkle tree - /// the leaves of the tree. pub fn hash_bytes(&self) -> Vec { - SimpleValidator::from(self).encode_vec().unwrap() + Protobuf::::encode_vec(&SimpleValidator::from(self)).unwrap() } } @@ -343,28 +238,134 @@ pub struct Update { pub power: vote::Power, } -impl Protobuf for Update {} +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +tendermint_pb_modules! { + use pb::{ + abci::ValidatorUpdate as RawValidatorUpdate, + types::{ + SimpleValidator as RawSimpleValidator, Validator as RawValidator, + ValidatorSet as RawValidatorSet, + }, + }; + use super::{Info, Set, SimpleValidator, Update}; + use crate::{prelude::*, Error}; + + impl Protobuf for Set {} + + impl TryFrom for Set { + type Error = Error; + + fn try_from(value: RawValidatorSet) -> Result { + let validators = value + .validators + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?; + + let proposer = value.proposer.map(TryInto::try_into).transpose()?; + let validator_set = Self::new(validators, proposer); + + // Ensure that the raw voting power matches the computed one + let raw_voting_power = value.total_voting_power.try_into()?; + if raw_voting_power != validator_set.total_voting_power() { + return Err(Error::raw_voting_power_mismatch( + raw_voting_power, + validator_set.total_voting_power(), + )); + } + + Ok(validator_set) + } + } + + impl From for RawValidatorSet { + fn from(value: Set) -> Self { + RawValidatorSet { + validators: value.validators.into_iter().map(Into::into).collect(), + proposer: value.proposer.map(Into::into), + total_voting_power: value.total_voting_power.into(), + } + } + } -impl From for RawValidatorUpdate { - fn from(vu: Update) -> Self { - Self { - pub_key: Some(vu.pub_key.into()), - power: vu.power.into(), + impl TryFrom for Info { + type Error = Error; + + fn try_from(value: RawValidator) -> Result { + Ok(Info { + address: value.address.try_into()?, + pub_key: value + .pub_key + .ok_or_else(Error::missing_public_key)? + .try_into()?, + power: value.voting_power.try_into()?, + name: None, + proposer_priority: value.proposer_priority.into(), + }) + } + } + + impl From for RawValidator { + fn from(value: Info) -> Self { + RawValidator { + address: value.address.into(), + pub_key: Some(value.pub_key.into()), + voting_power: value.power.into(), + proposer_priority: value.proposer_priority.into(), + } } } -} -impl TryFrom for Update { - type Error = Error; - - fn try_from(vu: RawValidatorUpdate) -> Result { - Ok(Self { - pub_key: vu - .pub_key - .ok_or_else(Error::missing_public_key)? - .try_into()?, - power: vu.power.try_into()?, - }) + impl Protobuf for SimpleValidator {} + + impl TryFrom for SimpleValidator { + type Error = Error; + + fn try_from(value: RawSimpleValidator) -> Result { + Ok(SimpleValidator { + pub_key: value.pub_key + .ok_or_else(Error::missing_public_key)? + .try_into()?, + voting_power: value.voting_power.try_into()?, + }) + } + } + + impl From for RawSimpleValidator { + fn from(value: SimpleValidator) -> Self { + RawSimpleValidator { + pub_key: Some(value.pub_key.into()), + voting_power: value.voting_power.into(), + } + } + } + + impl Protobuf for Update {} + + impl From for RawValidatorUpdate { + fn from(vu: Update) -> Self { + Self { + pub_key: Some(vu.pub_key.into()), + power: vu.power.into(), + } + } + } + + impl TryFrom for Update { + type Error = Error; + + fn try_from(vu: RawValidatorUpdate) -> Result { + Ok(Self { + pub_key: vu + .pub_key + .ok_or_else(Error::missing_public_key)? + .try_into()?, + power: vu.power.try_into()?, + }) + } } } diff --git a/tendermint/src/version.rs b/tendermint/src/version.rs index f814edf6c..364f5f6a9 100644 --- a/tendermint/src/version.rs +++ b/tendermint/src/version.rs @@ -13,3 +13,9 @@ impl Display for Version { write!(f, "{}", self.0) } } + +impl From for String { + fn from(value: Version) -> Self { + value.0 + } +} diff --git a/tendermint/src/vote.rs b/tendermint/src/vote.rs index 65d7a33df..fe5d32e13 100644 --- a/tendermint/src/vote.rs +++ b/tendermint/src/vote.rs @@ -5,15 +5,12 @@ mod power; mod sign_vote; mod validator_index; -use core::{ - convert::{TryFrom, TryInto}, - fmt, - str::FromStr, -}; +use core::{fmt, str::FromStr}; use bytes::BufMut; use serde::{Deserialize, Serialize}; -use tendermint_proto::{types::Vote as RawVote, Error as ProtobufError, Protobuf}; +use tendermint_proto::v0_37::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, @@ -55,44 +52,50 @@ pub struct Vote { pub signature: Option, } -impl Protobuf for Vote {} - -impl TryFrom for Vote { - type Error = Error; - - fn try_from(value: RawVote) -> Result { - if value.timestamp.is_none() { - return Err(Error::missing_timestamp()); +tendermint_pb_modules! { + use super::Vote; + use crate::{prelude::*, block, Error, Signature}; + use pb::types::Vote as RawVote; + + impl Protobuf for Vote {} + + impl TryFrom for Vote { + type Error = Error; + + fn try_from(value: RawVote) -> Result { + 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)?, + }) } - 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)?, - }) } -} -impl From 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.to_bytes()).unwrap_or_default(), + impl From 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.to_bytes()).unwrap_or_default(), + } } } } @@ -128,13 +131,15 @@ impl Vote { where B: BufMut, { - CanonicalVote::new(self.clone(), chain_id).encode_length_delimited(sign_bytes)?; + let canonical = CanonicalVote::new(self.clone(), chain_id); + Protobuf::::encode_length_delimited(&canonical, sign_bytes)?; Ok(true) } /// Create signable vector from Vote. pub fn to_signable_vec(&self, chain_id: ChainId) -> Result, ProtobufError> { - CanonicalVote::new(self.clone(), chain_id).encode_length_delimited_vec() + let canonical = CanonicalVote::new(self.clone(), chain_id); + Protobuf::::encode_length_delimited_vec(&canonical) } /// Consensus state from this vote - This doesn't seem to be used anywhere. @@ -213,7 +218,7 @@ impl SignedVote { /// Return the bytes (of the canonicalized vote) that were signed. pub fn sign_bytes(&self) -> Vec { - self.vote.encode_length_delimited_vec().unwrap() + Protobuf::::encode_length_delimited_vec(&self.vote).unwrap() } /// Return the actual signature on the canonicalized vote. diff --git a/tendermint/src/vote/canonical_vote.rs b/tendermint/src/vote/canonical_vote.rs index 363129003..c3afd918d 100644 --- a/tendermint/src/vote/canonical_vote.rs +++ b/tendermint/src/vote/canonical_vote.rs @@ -1,9 +1,7 @@ -use core::convert::{TryFrom, TryInto}; - use serde::{Deserialize, Serialize}; -use tendermint_proto::{types::CanonicalVote as RawCanonicalVote, Protobuf}; +use tendermint_proto::v0_37::types::CanonicalVote as RawCanonicalVote; -use crate::{block, chain::Id as ChainId, error::Error, prelude::*, Time}; +use crate::{block, chain::Id as ChainId, prelude::*, Time}; /// CanonicalVote is used for protobuf encoding a Vote #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] @@ -29,43 +27,50 @@ pub struct CanonicalVote { pub chain_id: ChainId, } -impl Protobuf for CanonicalVote {} - -impl TryFrom for CanonicalVote { - type Error = Error; - - fn try_from(value: RawCanonicalVote) -> Result { - if value.timestamp.is_none() { - return Err(Error::missing_timestamp()); +tendermint_pb_modules! { + use super::CanonicalVote; + use crate::Error; + use crate::{block, chain::Id as ChainId, prelude::*}; + use pb::types::CanonicalVote as RawCanonicalVote; + + impl Protobuf for CanonicalVote {} + + impl TryFrom for CanonicalVote { + type Error = Error; + + fn try_from(value: RawCanonicalVote) -> Result { + if value.timestamp.is_none() { + return Err(Error::missing_timestamp()); + } + let _val: i32 = value.round.try_into().map_err(Error::integer_overflow)?; + + // If the Hash is empty in BlockId, the BlockId should be empty. + // See: https://github.com/informalsystems/tendermint-rs/issues/663 + let block_id = value.block_id.filter(|i| !i.hash.is_empty()); + Ok(CanonicalVote { + vote_type: value.r#type.try_into()?, + height: value.height.try_into()?, + round: (value.round as i32).try_into()?, + block_id: block_id.map(|b| b.try_into()).transpose()?, + timestamp: value.timestamp.map(|t| t.try_into()).transpose()?, + chain_id: ChainId::try_from(value.chain_id)?, + }) } - let _val: i32 = value.round.try_into().map_err(Error::integer_overflow)?; - - // If the Hash is empty in BlockId, the BlockId should be empty. - // See: https://github.com/informalsystems/tendermint-rs/issues/663 - let block_id = value.block_id.filter(|i| !i.hash.is_empty()); - Ok(CanonicalVote { - vote_type: value.r#type.try_into()?, - height: value.height.try_into()?, - round: (value.round as i32).try_into()?, - block_id: block_id.map(|b| b.try_into()).transpose()?, - timestamp: value.timestamp.map(|t| t.try_into()).transpose()?, - chain_id: ChainId::try_from(value.chain_id)?, - }) } -} -impl From for RawCanonicalVote { - fn from(value: CanonicalVote) -> Self { - // If the Hash is empty in BlockId, the BlockId should be empty. - // See: https://github.com/informalsystems/tendermint-rs/issues/663 - let block_id = value.block_id.filter(|i| i != &block::Id::default()); - RawCanonicalVote { - r#type: value.vote_type.into(), - height: value.height.into(), - round: value.round.value().into(), - block_id: block_id.map(Into::into), - timestamp: value.timestamp.map(Into::into), - chain_id: value.chain_id.to_string(), + impl From for RawCanonicalVote { + fn from(value: CanonicalVote) -> Self { + // If the Hash is empty in BlockId, the BlockId should be empty. + // See: https://github.com/informalsystems/tendermint-rs/issues/663 + let block_id = value.block_id.filter(|i| i != &block::Id::default()); + RawCanonicalVote { + r#type: value.vote_type.into(), + height: value.height.into(), + round: value.round.value().into(), + block_id: block_id.map(Into::into), + timestamp: value.timestamp.map(Into::into), + chain_id: value.chain_id.to_string(), + } } } } @@ -86,52 +91,51 @@ impl CanonicalVote { #[cfg(test)] mod tests { - use core::convert::TryFrom; - use tendermint_proto::{ - google::protobuf::Timestamp, - types::{ + tendermint_pb_modules! { + use tendermint_proto::google::protobuf::Timestamp; + use pb::types::{ CanonicalBlockId as RawCanonicalBlockId, - CanonicalPartSetHeader as RawCanonicalPartSetHeader, CanonicalVote as RawCanonicalVote, - }, - }; - - use crate::{ - prelude::*, - vote::{canonical_vote::CanonicalVote, Type}, - }; - - #[test] - fn canonical_vote_domain_checks() { - // RawCanonicalVote with edge cases to test domain knowledge - // block_id with empty hash should decode to None - // timestamp at EPOCH is still considered valid time - let proto_cp = RawCanonicalVote { - r#type: 1, - height: 2, - round: 4, - block_id: Some(RawCanonicalBlockId { - hash: vec![], - part_set_header: Some(RawCanonicalPartSetHeader { - total: 1, - hash: vec![1], - }), - }), - timestamp: Some(Timestamp { - seconds: 0, - nanos: 0, - }), - chain_id: "testchain".to_string(), + CanonicalPartSetHeader as RawCanonicalPartSetHeader, + CanonicalVote as RawCanonicalVote, }; - let cp = CanonicalVote::try_from(proto_cp).unwrap(); - assert_eq!(cp.vote_type, Type::Prevote); - assert!(cp.block_id.is_none()); - assert!(cp.timestamp.is_some()); - - // No timestamp is not acceptable - // See: https://github.com/informalsystems/tendermint-rs/issues/649 - let mut proto_cp: RawCanonicalVote = cp.into(); - proto_cp.timestamp = None; - assert!(CanonicalVote::try_from(proto_cp).is_err()); + use crate::{ + prelude::*, + vote::{canonical_vote::CanonicalVote, Type}, + }; + + #[test] + fn canonical_vote_domain_checks() { + // RawCanonicalVote with edge cases to test domain knowledge + // block_id with empty hash should decode to None + // timestamp at EPOCH is still considered valid time + let proto_cp = RawCanonicalVote { + r#type: 1, + height: 2, + round: 4, + block_id: Some(RawCanonicalBlockId { + hash: vec![], + part_set_header: Some(RawCanonicalPartSetHeader { + total: 1, + hash: vec![1], + }), + }), + timestamp: Some(Timestamp { + seconds: 0, + nanos: 0, + }), + chain_id: "testchain".to_string(), + }; + let cp = CanonicalVote::try_from(proto_cp).unwrap(); + assert_eq!(cp.vote_type, Type::Prevote); + assert!(cp.block_id.is_none()); + assert!(cp.timestamp.is_some()); + + // No timestamp is not acceptable + // See: https://github.com/informalsystems/tendermint-rs/issues/649 + let mut proto_cp: RawCanonicalVote = cp.into(); + proto_cp.timestamp = None; + assert!(CanonicalVote::try_from(proto_cp).is_err()); + } } } diff --git a/tendermint/src/vote/sign_vote.rs b/tendermint/src/vote/sign_vote.rs index 7a257392c..e4707150c 100644 --- a/tendermint/src/vote/sign_vote.rs +++ b/tendermint/src/vote/sign_vote.rs @@ -1,15 +1,7 @@ -use core::convert::{TryFrom, TryInto}; - use bytes::BufMut; -use tendermint_proto::{ - privval::{ - RemoteSignerError, SignVoteRequest as RawSignVoteRequest, - SignedVoteResponse as RawSignedVoteResponse, - }, - Error as ProtobufError, Protobuf, -}; +use tendermint_proto::Error as ProtobufError; -use crate::{chain, error::Error, prelude::*, Vote}; +use crate::{chain, prelude::*, privval::RemoteSignerError, Vote}; /// SignVoteRequest is a request to sign a vote #[derive(Clone, PartialEq, Eq, Debug)] @@ -20,29 +12,6 @@ pub struct SignVoteRequest { pub chain_id: chain::Id, } -impl Protobuf for SignVoteRequest {} - -impl TryFrom for SignVoteRequest { - type Error = Error; - - fn try_from(value: RawSignVoteRequest) -> Result { - let vote = value.vote.ok_or_else(Error::no_vote_found)?.try_into()?; - - let chain_id = value.chain_id.try_into()?; - - Ok(SignVoteRequest { vote, chain_id }) - } -} - -impl From for RawSignVoteRequest { - fn from(value: SignVoteRequest) -> Self { - RawSignVoteRequest { - vote: Some(value.vote.into()), - chain_id: value.chain_id.as_str().to_string(), - } - } -} - impl SignVoteRequest { /// Create signable bytes from Vote. pub fn to_signable_bytes(&self, sign_bytes: &mut B) -> Result @@ -60,7 +29,7 @@ impl SignVoteRequest { } /// SignedVoteResponse is a response containing a signed vote or an error -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub struct SignedVoteResponse { /// Optional Vote pub vote: Option, @@ -68,24 +37,59 @@ pub struct SignedVoteResponse { pub error: Option, } -impl Protobuf for SignedVoteResponse {} +// ============================================================================= +// Protobuf conversions +// ============================================================================= -impl TryFrom for SignedVoteResponse { - type Error = Error; +tendermint_pb_modules! { + use super::{SignVoteRequest, SignedVoteResponse}; + use crate::{Error, prelude::*}; + use pb::privval::{ + SignVoteRequest as RawSignVoteRequest, SignedVoteResponse as RawSignedVoteResponse, + }; - fn try_from(value: RawSignedVoteResponse) -> Result { - Ok(SignedVoteResponse { - vote: value.vote.map(TryFrom::try_from).transpose()?, - error: value.error, - }) + impl Protobuf for SignVoteRequest {} + + impl TryFrom for SignVoteRequest { + type Error = Error; + + fn try_from(value: RawSignVoteRequest) -> Result { + let vote = value.vote.ok_or_else(Error::no_vote_found)?.try_into()?; + + let chain_id = value.chain_id.try_into()?; + + Ok(SignVoteRequest { vote, chain_id }) + } } -} -impl From for RawSignedVoteResponse { - fn from(value: SignedVoteResponse) -> Self { - RawSignedVoteResponse { - vote: value.vote.map(Into::into), - error: value.error, + impl From for RawSignVoteRequest { + fn from(value: SignVoteRequest) -> Self { + RawSignVoteRequest { + vote: Some(value.vote.into()), + chain_id: value.chain_id.as_str().to_owned(), + } + } + } + + impl Protobuf for SignedVoteResponse {} + + impl TryFrom for SignedVoteResponse { + type Error = Error; + + fn try_from(value: RawSignedVoteResponse) -> Result { + Ok(SignedVoteResponse { + vote: value.vote.map(TryFrom::try_from).transpose()?, + error: value.error.map(TryFrom::try_from).transpose()?, + }) + } + } + + impl From for RawSignedVoteResponse { + fn from(value: SignedVoteResponse) -> Self { + RawSignedVoteResponse { + vote: value.vote.map(Into::into), + error: value.error.map(Into::into), + } } } } @@ -98,7 +102,6 @@ mod tests { }; use std::println; - use tendermint_proto::Protobuf; use time::macros::datetime; use crate::{ @@ -272,169 +275,178 @@ mod tests { assert_eq!(got, want); } - #[test] - fn test_sign_bytes_compatibility() { - let cv = CanonicalVote::new(Vote::default(), ChainId::try_from("A").unwrap()); - let mut got = vec![]; - // SignBytes are encoded using MarshalBinary and not MarshalBinaryBare - cv.encode_length_delimited(&mut got).unwrap(); - let want = vec![ - 0x10, 0x8, 0x1, 0x11, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x32, 0x1, - 0x41, - ]; // Todo: Get these bytes from Go. During protobuf upgrade we didn't get to generate them. - assert_eq!(got, want); + tendermint_pb_modules! { + use super::*; + use pb::types::CanonicalVote as RawCanonicalVote; - // with proper (fixed size) height and round (Precommit): - { - let vt_precommit = Vote { - height: Height::from(1_u32), - round: Round::from(1_u16), - vote_type: Type::Precommit, - ..Default::default() - }; - println!("{vt_precommit:?}"); - let cv_precommit = CanonicalVote::new(vt_precommit, ChainId::try_from("A").unwrap()); - let got = cv_precommit.encode_vec().unwrap(); + #[test] + fn test_sign_bytes_compatibility() { + let cv = CanonicalVote::new(Vote::default(), ChainId::try_from("A").unwrap()); + let mut got = vec![]; + // SignBytes are encoded using MarshalBinary and not MarshalBinaryBare + Protobuf::::encode_length_delimited(&cv, &mut got).unwrap(); let want = vec![ - 0x8, // (field_number << 3) | wire_type - 0x2, // PrecommitType - 0x11, // (field_number << 3) | wire_type - 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height - 0x19, // (field_number << 3) | wire_type - 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round - 0x2a, // (field_number << 3) | wire_type - 0x0, // timestamp - 0x32, // (field_number << 3) | wire_type - // remaining fields (chain ID): - 0x1, 0x41, - ]; + 0x10, 0x8, 0x1, 0x11, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x32, 0x1, + 0x41, + ]; // Todo: Get these bytes from Go. During protobuf upgrade we didn't get to generate them. assert_eq!(got, want); - } - // with proper (fixed size) height and round (Prevote): - { - let vt_prevote = Vote { - height: Height::from(1_u32), - round: Round::from(1_u16), - vote_type: Type::Prevote, - ..Default::default() - }; - let cv_prevote = CanonicalVote::new(vt_prevote, ChainId::try_from("A").unwrap()); - - let got = cv_prevote.encode_vec().unwrap(); - - let want = vec![ - 0x8, // (field_number << 3) | wire_type - 0x1, // PrevoteType - 0x11, // (field_number << 3) | wire_type - 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height - 0x19, // (field_number << 3) | wire_type - 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round - 0x2a, // (field_number << 3) | wire_type - 0x0, // timestamp - 0x32, // (field_number << 3) | wire_type - // remaining fields (chain ID): - 0x1, 0x41, - ]; - assert_eq!(got, want); + // with proper (fixed size) height and round (Precommit): + { + let vt_precommit = Vote { + height: Height::from(1_u32), + round: Round::from(1_u16), + vote_type: Type::Precommit, + ..Default::default() + }; + println!("{vt_precommit:?}"); + let cv_precommit = CanonicalVote::new(vt_precommit, ChainId::try_from("A").unwrap()); + let got = Protobuf::::encode_vec(&cv_precommit).unwrap(); + let want = vec![ + 0x8, // (field_number << 3) | wire_type + 0x2, // PrecommitType + 0x11, // (field_number << 3) | wire_type + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height + 0x19, // (field_number << 3) | wire_type + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round + 0x2a, // (field_number << 3) | wire_type + 0x0, // timestamp + 0x32, // (field_number << 3) | wire_type + // remaining fields (chain ID): + 0x1, 0x41, + ]; + assert_eq!(got, want); + } + // with proper (fixed size) height and round (Prevote): + { + let vt_prevote = Vote { + height: Height::from(1_u32), + round: Round::from(1_u16), + vote_type: Type::Prevote, + ..Default::default() + }; + + let cv_prevote = CanonicalVote::new(vt_prevote, ChainId::try_from("A").unwrap()); + + let got = Protobuf::::encode_vec(&cv_prevote).unwrap(); + + let want = vec![ + 0x8, // (field_number << 3) | wire_type + 0x1, // PrevoteType + 0x11, // (field_number << 3) | wire_type + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height + 0x19, // (field_number << 3) | wire_type + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round + 0x2a, // (field_number << 3) | wire_type + 0x0, // timestamp + 0x32, // (field_number << 3) | wire_type + // remaining fields (chain ID): + 0x1, 0x41, + ]; + assert_eq!(got, want); + } } - } - #[test] - fn test_vote_rountrip_with_sig() { - let dt = datetime!(2017-12-25 03:00:01.234 UTC); - let vote = Vote { - validator_address: AccountId::try_from(vec![ - 0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, 0xf4, - 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35, - ]) - .unwrap(), - validator_index: ValidatorIndex::try_from(56789).unwrap(), - height: Height::from(12345_u32), - round: Round::from(2_u16), - timestamp: Some(dt.try_into().unwrap()), - vote_type: Type::Prevote, - block_id: Some(BlockId { - hash: Hash::from_hex_upper(Algorithm::Sha256, "DEADBEEFDEADBEEFBAFBAFBAFBAFBAFA") - .unwrap(), // Hash::new(Algorithm::Sha256, - // b"hash".to_vec().as_slice()).unwrap(), - part_set_header: Header::new( - 1_000_000, - Hash::from_hex_upper(Algorithm::Sha256, "DEADBEEFDEADBEEFBAFBAFBAFBAFBAFA") - .unwrap(), - ) + #[test] + fn test_deserialization() { + let encoded = vec![ + 10, 188, 1, 8, 1, 16, 185, 96, 24, 2, 34, 74, 10, 32, 222, 173, 190, 239, 222, 173, + 190, 239, 186, 251, 175, 186, 251, 175, 186, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 18, 38, 8, 192, 132, 61, 18, 32, 0, 34, 68, 102, 136, 170, 204, 238, 17, + 51, 85, 119, 153, 187, 221, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, + 11, 8, 177, 211, 129, 210, 5, 16, 128, 157, 202, 111, 50, 20, 163, 178, 204, 221, 113, + 134, 241, 104, 95, 33, 242, 72, 42, 244, 251, 52, 70, 168, 75, 53, 56, 213, 187, 3, 66, + 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 18, 13, 116, 101, 115, 116, 95, 99, 104, 97, 105, 110, 95, 105, + 100, + ]; // Todo: Double-check the Go implementation, this was self-generated. + let dt = datetime!(2017-12-25 03:00:01.234 UTC); + let vote = Vote { + validator_address: AccountId::try_from(vec![ + 0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, 0xf4, + 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35, + ]) .unwrap(), - }), - // signature: None, - signature: Signature::new(vec![ - 130u8, 246, 183, 50, 153, 248, 28, 57, 51, 142, 55, 217, 194, 24, 134, 212, 233, - 100, 211, 10, 24, 174, 179, 117, 41, 65, 141, 134, 149, 239, 65, 174, 217, 42, 6, - 184, 112, 17, 7, 97, 255, 221, 252, 16, 60, 144, 30, 212, 167, 39, 67, 35, 118, - 192, 133, 130, 193, 115, 32, 206, 152, 91, 173, 10, - ]) - .unwrap(), - }; - let got = vote.encode_vec().unwrap(); - let v = Vote::decode_vec(&got).unwrap(); - - assert_eq!(v, vote); - // SignVoteRequest - { - let svr = SignVoteRequest { + validator_index: ValidatorIndex::try_from(56789).unwrap(), + height: Height::from(12345_u32), + round: Round::from(2_u16), + timestamp: Some(dt.try_into().unwrap()), + vote_type: Type::Prevote, + block_id: Some(BlockId { + hash: Hash::from_hex_upper(Algorithm::Sha256, "DEADBEEFDEADBEEFBAFBAFBAFBAFBAFA") + .unwrap(), + part_set_header: Header::new( + 1_000_000, + Hash::from_hex_upper(Algorithm::Sha256, "0022446688AACCEE1133557799BBDDFF") + .unwrap(), + ) + .unwrap(), + }), + signature: Signature::new(vec![1; Ed25519Signature::BYTE_SIZE]).unwrap(), + }; + let want = SignVoteRequest { vote, chain_id: ChainId::from_str("test_chain_id").unwrap(), }; - let mut got = vec![]; - let _have = svr.encode(&mut got); - - let svr2 = SignVoteRequest::decode(got.as_ref()).unwrap(); - assert_eq!(svr, svr2); + let got = >::decode_vec( + &encoded + ).unwrap(); + assert_eq!(got, want); } - } - #[test] - fn test_deserialization() { - let encoded = vec![ - 10, 188, 1, 8, 1, 16, 185, 96, 24, 2, 34, 74, 10, 32, 222, 173, 190, 239, 222, 173, - 190, 239, 186, 251, 175, 186, 251, 175, 186, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 18, 38, 8, 192, 132, 61, 18, 32, 0, 34, 68, 102, 136, 170, 204, 238, 17, - 51, 85, 119, 153, 187, 221, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, - 11, 8, 177, 211, 129, 210, 5, 16, 128, 157, 202, 111, 50, 20, 163, 178, 204, 221, 113, - 134, 241, 104, 95, 33, 242, 72, 42, 244, 251, 52, 70, 168, 75, 53, 56, 213, 187, 3, 66, - 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 18, 13, 116, 101, 115, 116, 95, 99, 104, 97, 105, 110, 95, 105, - 100, - ]; // Todo: Double-check the Go implementation, this was self-generated. - let dt = datetime!(2017-12-25 03:00:01.234 UTC); - let vote = Vote { - validator_address: AccountId::try_from(vec![ - 0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, 0xf4, - 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35, - ]) - .unwrap(), - validator_index: ValidatorIndex::try_from(56789).unwrap(), - height: Height::from(12345_u32), - round: Round::from(2_u16), - timestamp: Some(dt.try_into().unwrap()), - vote_type: Type::Prevote, - block_id: Some(BlockId { - hash: Hash::from_hex_upper(Algorithm::Sha256, "DEADBEEFDEADBEEFBAFBAFBAFBAFBAFA") + #[test] + fn test_vote_rountrip_with_sig() { + let dt = datetime!(2017-12-25 03:00:01.234 UTC); + let vote = Vote { + validator_address: AccountId::try_from(vec![ + 0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, 0xf4, + 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35, + ]) + .unwrap(), + validator_index: ValidatorIndex::try_from(56789).unwrap(), + height: Height::from(12345_u32), + round: Round::from(2_u16), + timestamp: Some(dt.try_into().unwrap()), + vote_type: Type::Prevote, + block_id: Some(BlockId { + hash: Hash::from_hex_upper(Algorithm::Sha256, "DEADBEEFDEADBEEFBAFBAFBAFBAFBAFA") + .unwrap(), // Hash::new(Algorithm::Sha256, + // b"hash".to_vec().as_slice()).unwrap(), + part_set_header: Header::new( + 1_000_000, + Hash::from_hex_upper(Algorithm::Sha256, "DEADBEEFDEADBEEFBAFBAFBAFBAFBAFA") + .unwrap(), + ) .unwrap(), - part_set_header: Header::new( - 1_000_000, - Hash::from_hex_upper(Algorithm::Sha256, "0022446688AACCEE1133557799BBDDFF") - .unwrap(), - ) + }), + // signature: None, + signature: Signature::new(vec![ + 130u8, 246, 183, 50, 153, 248, 28, 57, 51, 142, 55, 217, 194, 24, 134, 212, 233, + 100, 211, 10, 24, 174, 179, 117, 41, 65, 141, 134, 149, 239, 65, 174, 217, 42, 6, + 184, 112, 17, 7, 97, 255, 221, 252, 16, 60, 144, 30, 212, 167, 39, 67, 35, 118, + 192, 133, 130, 193, 115, 32, 206, 152, 91, 173, 10, + ]) .unwrap(), - }), - signature: Signature::new(vec![1; Ed25519Signature::BYTE_SIZE]).unwrap(), - }; - let want = SignVoteRequest { - vote, - chain_id: ChainId::from_str("test_chain_id").unwrap(), - }; - let got = SignVoteRequest::decode_vec(&encoded).unwrap(); - assert_eq!(got, want); + }; + let got = Protobuf::::encode_vec(&vote).unwrap(); + let v = >::decode_vec(&got).unwrap(); + + assert_eq!(v, vote); + // SignVoteRequest + { + let svr = SignVoteRequest { + vote, + chain_id: ChainId::from_str("test_chain_id").unwrap(), + }; + let mut got = vec![]; + let _have = Protobuf::::encode(&svr, &mut got); + + let svr2 = >::decode( + got.as_ref() + ).unwrap(); + assert_eq!(svr, svr2); + } + } } } diff --git a/test/src/test/unit/p2p/secret_connection.rs b/test/src/test/unit/p2p/secret_connection.rs index 44dfb68af..75f16f231 100644 --- a/test/src/test/unit/p2p/secret_connection.rs +++ b/test/src/test/unit/p2p/secret_connection.rs @@ -6,7 +6,7 @@ use std::{ use rand_core::OsRng; use tendermint_p2p::secret_connection::{sort32, Handshake, SecretConnection, Version}; -use tendermint_proto as proto; +use tendermint_proto::v0_37 as proto; use x25519_dalek::PublicKey as EphemeralPublic; use crate::pipe; diff --git a/tools/kvstore-test/tests/tendermint.rs b/tools/kvstore-test/tests/tendermint.rs index 8a78ec458..4a13a27e0 100644 --- a/tools/kvstore-test/tests/tendermint.rs +++ b/tools/kvstore-test/tests/tendermint.rs @@ -30,7 +30,6 @@ mod rpc { merkle::simple_hash_from_byte_vectors, }; use tendermint_rpc::{ - endpoint::tx::Response as ResultTx, event::{Event, EventData, TxInfo}, query::{EventType, Query}, Client, HttpClient, Id, Order, SubscriptionClient, WebSocketClient, WebSocketClientDriver, @@ -462,7 +461,7 @@ mod rpc { .txs .iter() .filter(|tx| tx.height.value() == (tx_info.height as u64)) - .collect::>(); + .collect::>(); assert_eq!(1, txs.len()); assert_eq!(tx_info.tx, txs[0].tx); diff --git a/tools/proto-compiler/Cargo.toml b/tools/proto-compiler/Cargo.toml index 4b351b12c..c844577f1 100644 --- a/tools/proto-compiler/Cargo.toml +++ b/tools/proto-compiler/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "tendermint-proto-compiler" -version = "0.1.0" +version = "0.2.0" authors = ["Informal Systems "] edition = "2021" publish = false [dependencies] walkdir = { version = "2.3" } -prost-build = { version = "0.11" } +prost-build = { version = "0.11.4" } git2 = { version = "0.16" } tempfile = { version = "3.2.0" } subtle-encoding = { version = "0.5" } diff --git a/tools/proto-compiler/src/constants.rs b/tools/proto-compiler/src/constants.rs index d46458e23..556f9d8b4 100644 --- a/tools/proto-compiler/src/constants.rs +++ b/tools/proto-compiler/src/constants.rs @@ -2,11 +2,30 @@ /// Tendermint repository URL. pub const TENDERMINT_REPO: &str = "https://github.com/tendermint/tendermint"; -// Commitish formats: -// Tag: v0.34.0-rc4 -// Branch: master -// Commit ID (full length): d7d0ffea13c60c98b812d243ba5a2c375f341c15 -pub const TENDERMINT_COMMITISH: &str = "v0.34.21"; + +/// Information on a Tendermint snapshot to generate prost structures from. +pub struct TendermintVersion { + /// Identifier to use in module names. + pub ident: &'static str, + /// A commitish reference in the tendermint git repository, for example: + /// + /// - Tag: `v0.34.0-rc4` + /// - Branch: `main` + /// - Commit ID (full length): `d7d0ffea13c60c98b812d243ba5a2c375f341c15` + pub commitish: &'static str, +} + +/// All Tendermint versions to generate code for +pub const TENDERMINT_VERSIONS: &[TendermintVersion] = &[ + TendermintVersion { + ident: "v0_34", + commitish: "v0.34.24", + }, + TendermintVersion { + ident: "v0_37", + commitish: "v0.37.0-alpha.1", + }, +]; /// Predefined custom attributes for message annotations const PRIMITIVE_ENUM: &str = r#"#[derive(::num_derive::FromPrimitive, ::num_derive::ToPrimitive)]"#; @@ -34,7 +53,6 @@ const RENAME_SRPUBKEY: &str = r#"#[serde(rename = "tendermint/PubKeySr25519", wi const RENAME_DUPLICATEVOTE: &str = r#"#[serde(rename = "tendermint/DuplicateVoteEvidence")]"#; const RENAME_LIGHTCLIENTATTACK: &str = r#"#[serde(rename = "tendermint/LightClientAttackEvidence")]"#; -const EVIDENCE_VARIANT: &str = r#"#[serde(from = "crate::serializers::evidence::EvidenceVariant", into = "crate::serializers::evidence::EvidenceVariant")]"#; const ALIAS_VALIDATOR_POWER_QUOTED: &str = r#"#[serde(alias = "ValidatorPower", with = "crate::serializers::from_str")]"#; const ALIAS_TOTAL_VOTING_POWER_QUOTED: &str = @@ -53,8 +71,9 @@ pub static CUSTOM_TYPE_ATTRIBUTES: &[(&str, &str)] = &[ (".tendermint.types.BlockIDFlag", PRIMITIVE_ENUM), (".tendermint.types.Block", SERIALIZED), (".tendermint.types.Data", SERIALIZED), + (".tendermint.types.Evidence.sum", SERIALIZED), + (".tendermint.types.Evidence.sum", TYPE_TAG), (".tendermint.types.EvidenceList", SERIALIZED), - (".tendermint.types.Evidence", SERIALIZED), (".tendermint.types.DuplicateVoteEvidence", SERIALIZED), (".tendermint.types.Vote", SERIALIZED), (".tendermint.types.BlockID", SERIALIZED), @@ -69,14 +88,12 @@ pub static CUSTOM_TYPE_ATTRIBUTES: &[(&str, &str)] = &[ (".tendermint.types.ValidatorSet", SERIALIZED), (".tendermint.crypto.PublicKey", SERIALIZED), (".tendermint.crypto.PublicKey.sum", TYPE_TAG), - (".tendermint.types.Evidence.sum", TYPE_TAG), (".tendermint.abci.ResponseInfo", SERIALIZED), (".tendermint.types.CanonicalBlockID", SERIALIZED), (".tendermint.types.CanonicalPartSetHeader", SERIALIZED), (".tendermint.types.Validator", SERIALIZED), (".tendermint.types.CanonicalVote", SERIALIZED), (".tendermint.types.BlockMeta", SERIALIZED), - (".tendermint.types.Evidence", EVIDENCE_VARIANT), (".tendermint.types.TxProof", SERIALIZED), (".tendermint.crypto.Proof", SERIALIZED), ]; diff --git a/tools/proto-compiler/src/functions.rs b/tools/proto-compiler/src/functions.rs index 877b9f02d..e38edb2ca 100644 --- a/tools/proto-compiler/src/functions.rs +++ b/tools/proto-compiler/src/functions.rs @@ -1,4 +1,5 @@ use std::{ + collections::BTreeSet, fs::{copy, create_dir_all, remove_dir_all, File}, io::Write, path::{Path, PathBuf}, @@ -11,6 +12,8 @@ use git2::{ use subtle_encoding::hex; use walkdir::WalkDir; +use crate::constants::TendermintVersion; + /// Clone or open+fetch a repository and check out a specific commitish /// In case of an existing repository, the origin remote will be set to `url`. pub fn get_commitish(dir: &Path, url: &str, commitish: &str) { @@ -163,20 +166,20 @@ pub fn copy_files(src_dir: &Path, target_dir: &Path) { // Copy new compiled files (prost does not use folder structures) let errors = WalkDir::new(src_dir) + .contents_first(true) .into_iter() - .filter_map(|e| e.ok()) - .filter(|e| e.file_type().is_file()) - .map(|e| { - copy( - e.path(), - std::path::Path::new(&format!( - "{}/{}", - &target_dir.display(), - &e.file_name().to_os_string().to_str().unwrap() - )), - ) + .filter_entry(|e| { + e.file_type().is_file() + && e.file_name() + .to_str() + .map(|name| name.starts_with("tendermint.")) + .unwrap_or(false) }) - .filter_map(|e| e.err()) + .map(|res| { + let e = res?; + copy(e.path(), target_dir.join(e.file_name())) + }) + .filter_map(|res| res.err()) .collect::>(); if !errors.is_empty() { @@ -207,8 +210,10 @@ pub fn find_proto_files(proto_paths: Vec) -> Vec { protos } -/// Create tendermint.rs with library information -pub fn generate_tendermint_lib(prost_dir: &Path, tendermint_lib_target: &Path) { +/// Create a module including generated content for the specified +/// Tendermint source version. +pub fn generate_tendermint_mod(prost_dir: &Path, version: &TendermintVersion, target_dir: &Path) { + create_dir_all(target_dir).unwrap(); let file_names = WalkDir::new(prost_dir) .into_iter() .filter_map(|e| e.ok()) @@ -217,8 +222,9 @@ pub fn generate_tendermint_lib(prost_dir: &Path, tendermint_lib_target: &Path) { && e.file_name().to_str().unwrap().starts_with("tendermint.") && e.file_name().to_str().unwrap().ends_with(".rs") }) - .map(|d| d.file_name().to_str().unwrap().to_string()) - .collect::>(); + .map(|d| d.file_name().to_str().unwrap().to_owned()) + .collect::>(); + let file_names = Vec::from_iter(file_names); let mut content = String::from("//! Tendermint-proto auto-generated sub-modules for Tendermint\n"); @@ -237,8 +243,9 @@ pub fn generate_tendermint_lib(prost_dir: &Path, tendermint_lib_target: &Path) { let mut tab_count = parts.len(); let mut inner_content = format!( - "{}include!(\"prost/{}\");", + "{}include!(\"../prost/{}/{}\");", tab.repeat(tab_count), + &version.ident, file_name ); @@ -261,11 +268,22 @@ pub fn generate_tendermint_lib(prost_dir: &Path, tendermint_lib_target: &Path) { tab, crate::constants::TENDERMINT_REPO, tab, - crate::constants::TENDERMINT_COMMITISH, + &version.commitish, ); + let tendermint_mod_target = target_dir.join(format!("{}.rs", version.ident)); let mut file = - File::create(tendermint_lib_target).expect("tendermint library file create failed"); + File::create(tendermint_mod_target).expect("tendermint module file create failed"); file.write_all(content.as_bytes()) - .expect("tendermint library file write failed"); + .expect("tendermint module file write failed"); +} + +pub fn generate_tendermint_lib(versions: &[TendermintVersion], tendermint_lib_target: &Path) { + let mut file = + File::create(tendermint_lib_target).expect("tendermint library file create failed"); + for version in versions { + writeln!(&mut file, "pub mod {};", version.ident).unwrap(); + } + let last_version = versions.last().unwrap(); + writeln!(&mut file, "pub use {}::*;", last_version.ident).unwrap(); } diff --git a/tools/proto-compiler/src/main.rs b/tools/proto-compiler/src/main.rs index 2ac1b954d..0ff9c2eb5 100644 --- a/tools/proto-compiler/src/main.rs +++ b/tools/proto-compiler/src/main.rs @@ -1,33 +1,24 @@ -use std::{env::var, path::PathBuf}; +use std::{ + env::var, + path::{Path, PathBuf}, + process, +}; use tempfile::tempdir; mod functions; -use functions::{copy_files, find_proto_files, generate_tendermint_lib, get_commitish}; +use functions::{ + copy_files, find_proto_files, generate_tendermint_lib, generate_tendermint_mod, get_commitish, +}; mod constants; use constants::{ - CUSTOM_FIELD_ATTRIBUTES, CUSTOM_TYPE_ATTRIBUTES, TENDERMINT_COMMITISH, TENDERMINT_REPO, + CUSTOM_FIELD_ATTRIBUTES, CUSTOM_TYPE_ATTRIBUTES, TENDERMINT_REPO, TENDERMINT_VERSIONS, }; fn main() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let tendermint_lib_target = root - .join("..") - .join("..") - .join("proto") - .join("src") - .join("tendermint.rs"); - let target_dir = root - .join("..") - .join("..") - .join("proto") - .join("src") - .join("prost"); - let out_dir = var("OUT_DIR") - .map(PathBuf::from) - .or_else(|_| tempdir().map(|d| d.into_path())) - .unwrap(); + let target_dir = ["..", "..", "proto", "src"].iter().collect::(); let tendermint_dir = PathBuf::from(var("TENDERMINT_DIR").unwrap_or_else(|_| { root.join("..") .join("target") @@ -37,53 +28,70 @@ fn main() { .to_string() })); - println!( - "[info] => Fetching {TENDERMINT_REPO} at {TENDERMINT_COMMITISH} into {tendermint_dir:?}" - ); - get_commitish( - &PathBuf::from(&tendermint_dir), - TENDERMINT_REPO, - TENDERMINT_COMMITISH, - ); // This panics if it fails. + for version in TENDERMINT_VERSIONS { + println!( + "[info] => Fetching {TENDERMINT_REPO} at {} into {tendermint_dir:?}", + &version.commitish, + ); + get_commitish(&tendermint_dir, TENDERMINT_REPO, &version.commitish); // This panics if it fails. - let proto_paths = vec![tendermint_dir.join("proto")]; - let proto_includes_paths = vec![ - tendermint_dir.join("proto"), - tendermint_dir.join("third_party").join("proto"), - ]; - // List available proto files - let protos = find_proto_files(proto_paths); + let proto_paths = vec![tendermint_dir.join("proto")]; + let proto_includes_paths = vec![ + tendermint_dir.join("proto"), + tendermint_dir.join("third_party").join("proto"), + ]; + // List available proto files + let protos = find_proto_files(proto_paths); - let mut pb = prost_build::Config::new(); + let ver_target_dir = target_dir.join("prost").join(&version.ident); + let ver_module_dir = target_dir.join("tendermint"); - // Use shared Bytes buffers for ABCI messages: - pb.bytes([".tendermint.abci"]); + let out_dir = var("OUT_DIR") + .map(|d| Path::new(&d).join(&version.ident)) + .or_else(|_| tempdir().map(|d| d.into_path())) + .unwrap(); - // Compile proto files with added annotations, exchange prost_types to our own - pb.out_dir(&out_dir); - for type_attribute in CUSTOM_TYPE_ATTRIBUTES { - pb.type_attribute(type_attribute.0, type_attribute.1); - } - for field_attribute in CUSTOM_FIELD_ATTRIBUTES { - pb.field_attribute(field_attribute.0, field_attribute.1); - } - // The below in-place path redirection replaces references to the Duration - // and Timestamp WKTs with our own versions that have valid doctest comments. - // See also https://github.com/danburkert/prost/issues/374 . - pb.extern_path( - ".google.protobuf.Duration", - "super::super::google::protobuf::Duration", - ); - pb.extern_path( - ".google.protobuf.Timestamp", - "super::super::google::protobuf::Timestamp", - ); - println!("[info] => Creating structs."); - pb.compile_protos(&protos, &proto_includes_paths).unwrap(); + let mut pb = prost_build::Config::new(); - println!("[info] => Removing old structs and copying new structs."); - copy_files(&out_dir, &target_dir); // This panics if it fails. - generate_tendermint_lib(&out_dir, &tendermint_lib_target); + // Use shared Bytes buffers for ABCI messages: + pb.bytes(&[".tendermint.abci"]); + + // Compile proto files with added annotations, exchange prost_types to our own + pb.out_dir(&out_dir); + for type_attribute in CUSTOM_TYPE_ATTRIBUTES { + pb.type_attribute(type_attribute.0, type_attribute.1); + } + for field_attribute in CUSTOM_FIELD_ATTRIBUTES { + pb.field_attribute(field_attribute.0, field_attribute.1); + } + // The below in-place path redirection replaces references to the Duration + // and Timestamp WKTs with our own versions that have valid doctest comments. + // See also https://github.com/danburkert/prost/issues/374 . + pb.extern_path( + ".google.protobuf.Duration", + "crate::google::protobuf::Duration", + ); + pb.extern_path( + ".google.protobuf.Timestamp", + "crate::google::protobuf::Timestamp", + ); + println!("[info] => Creating structs."); + match pb.compile_protos(&protos, &proto_includes_paths) { + Ok(()) => {}, + Err(e) => { + eprintln!("{}", e); + process::exit(1); + }, + } + + println!( + "[info] => Removing old structs and copying new structs to {}", + ver_target_dir.to_string_lossy(), + ); + copy_files(&out_dir, &ver_target_dir); // This panics if it fails. + generate_tendermint_mod(&out_dir, &version, &ver_module_dir); + } + generate_tendermint_lib(TENDERMINT_VERSIONS, &target_dir.join("tendermint.rs")); println!("[info] => Done!"); } diff --git a/tools/rpc-probe/Makefile.toml b/tools/rpc-probe/Makefile.toml index 1c71a74c3..bb4d28c19 100644 --- a/tools/rpc-probe/Makefile.toml +++ b/tools/rpc-probe/Makefile.toml @@ -1,8 +1,9 @@ [env] CONTAINER_NAME = "kvstore-rpc-probe" -DOCKER_IMAGE = "informaldev/tendermint:0.34.21" +DOCKER_IMAGE = "cometbft/cometbft:v0.37.x" HOST_RPC_PORT = 26657 CARGO_MAKE_WAIT_MILLISECONDS = 3500 +OUTPUT_DIR = "fixtures" [tasks.default] clear = true @@ -10,7 +11,7 @@ dependencies = [ "docker-up", "wait", "run", "docker-down" ] [tasks.run] command = "cargo" -args = ["run", "kvstore"] +args = ["run", "--", "--verbose", "--output", "${OUTPUT_DIR}", "kvstore"] [tasks.docker-down] dependencies = [ "docker-stop", "docker-rm" ] diff --git a/tools/rpc-probe/README.md b/tools/rpc-probe/README.md index 2cd62b654..f7679452e 100644 --- a/tools/rpc-probe/README.md +++ b/tools/rpc-probe/README.md @@ -37,7 +37,7 @@ This will: To run a specific version of Tendermint, simply: ```bash -DOCKER_IMAGE="informaldev/tendermint:v0.34.0" cargo make +cargo make --env DOCKER_IMAGE="informaldev/tendermint:v0.34.0" ``` ## Usage (without Docker) diff --git a/tools/rpc-probe/src/kvstore.rs b/tools/rpc-probe/src/kvstore.rs index f6186cc51..e8230d849 100644 --- a/tools/rpc-probe/src/kvstore.rs +++ b/tools/rpc-probe/src/kvstore.rs @@ -26,7 +26,8 @@ pub fn quick_probe_plan(output_path: &Path, request_wait: Duration) -> Result 1", 1, 100, "asc").with_name("block_search"), blockchain(1, 10).with_name("blockchain_from_1_to_10"), diff --git a/tools/rpc-probe/src/plan.rs b/tools/rpc-probe/src/plan.rs index 982ef9a09..6212cc680 100644 --- a/tools/rpc-probe/src/plan.rs +++ b/tools/rpc-probe/src/plan.rs @@ -369,6 +369,8 @@ async fn execute_request( request: Request, ) -> Result<()> { let request_json = request.as_json(); + debug!("Sending outgoing request: {}", request_json); + write_json(&config.out_path, name, &request_json).await?; let response_json = match client.request(&request_json).await { Ok(r) => {