From 04e3327e24851ee109208574f8e8db3ec1d05186 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Wed, 16 Nov 2022 15:20:57 +0200 Subject: [PATCH 1/8] rpc: remove use of tendermint_proto::serializers Import tendermint::serializers instead. This removes almost all need to depend on tendermint_proto directly. --- rpc/src/endpoint/block_search.rs | 8 ++++---- rpc/src/endpoint/tx_search.rs | 8 ++++---- rpc/src/endpoint/validators.rs | 8 ++++---- rpc/src/event.rs | 6 +++--- rpc/src/query.rs | 3 +-- rpc/src/serializers.rs | 2 +- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/rpc/src/endpoint/block_search.rs b/rpc/src/endpoint/block_search.rs index a9ff5635e..dad8d8add 100644 --- a/rpc/src/endpoint/block_search.rs +++ b/rpc/src/endpoint/block_search.rs @@ -3,15 +3,15 @@ use serde::{Deserialize, Serialize}; pub use super::{block, block_results}; -use crate::{prelude::*, Method, Order}; +use crate::{prelude::*, serializers, Method, Order}; /// Request for searching for blocks by their BeginBlock and EndBlock events. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Request { pub query: String, - #[serde(with = "tendermint_proto::serializers::from_str")] + #[serde(with = "serializers::from_str")] pub page: u32, - #[serde(with = "tendermint_proto::serializers::from_str")] + #[serde(with = "serializers::from_str")] pub per_page: u8, pub order_by: Order, } @@ -41,7 +41,7 @@ impl crate::SimpleRequest for Request {} #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Response { pub blocks: Vec, - #[serde(with = "tendermint_proto::serializers::from_str")] + #[serde(with = "serializers::from_str")] pub total_count: u32, } diff --git a/rpc/src/endpoint/tx_search.rs b/rpc/src/endpoint/tx_search.rs index 198e06f9a..b59ca2475 100644 --- a/rpc/src/endpoint/tx_search.rs +++ b/rpc/src/endpoint/tx_search.rs @@ -3,16 +3,16 @@ use serde::{Deserialize, Serialize}; pub use super::tx; -use crate::{prelude::*, Method, Order}; +use crate::{prelude::*, serializers, Method, Order}; /// Request for searching for transactions with their results. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Request { pub query: String, pub prove: bool, - #[serde(with = "tendermint_proto::serializers::from_str")] + #[serde(with = "serializers::from_str")] pub page: u32, - #[serde(with = "tendermint_proto::serializers::from_str")] + #[serde(with = "serializers::from_str")] pub per_page: u8, pub order_by: Order, } @@ -49,7 +49,7 @@ impl crate::SimpleRequest for Request {} #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Response { pub txs: Vec, - #[serde(with = "tendermint_proto::serializers::from_str")] + #[serde(with = "serializers::from_str")] pub total_count: u32, } diff --git a/rpc/src/endpoint/validators.rs b/rpc/src/endpoint/validators.rs index 3c8559c83..d71cf915d 100644 --- a/rpc/src/endpoint/validators.rs +++ b/rpc/src/endpoint/validators.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use tendermint::{block, validator}; -use crate::{prelude::*, PageNumber, PerPage}; +use crate::{prelude::*, serializers, PageNumber, PerPage}; /// The default number of validators to return per page. pub const DEFAULT_VALIDATORS_PER_PAGE: u8 = 30; @@ -16,10 +16,10 @@ pub struct Request { /// defaults to the latest height. pub height: Option, /// The number of the page to fetch. - #[serde(with = "tendermint_proto::serializers::optional_from_str")] + #[serde(with = "serializers::optional_from_str")] pub page: Option, /// The number of validators to fetch per page. - #[serde(with = "tendermint_proto::serializers::optional_from_str")] + #[serde(with = "serializers::optional_from_str")] pub per_page: Option, } @@ -64,7 +64,7 @@ pub struct Response { pub validators: Vec, /// Total number of validators for this block height. - #[serde(with = "tendermint_proto::serializers::from_str")] + #[serde(with = "serializers::from_str")] pub total: i32, } diff --git a/rpc/src/event.rs b/rpc/src/event.rs index c69d9c3df..5ce997796 100644 --- a/rpc/src/event.rs +++ b/rpc/src/event.rs @@ -5,7 +5,7 @@ use alloc::collections::BTreeMap as HashMap; use serde::{Deserialize, Serialize}; use tendermint::{abci, Block}; -use crate::{prelude::*, query::EventType, response::Wrapper, Response}; +use crate::{prelude::*, query::EventType, response::Wrapper, serializers, Response}; /// An incoming event produced by a [`Subscription`]. /// @@ -59,10 +59,10 @@ pub enum EventData { /// Transaction result info. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct TxInfo { - #[serde(with = "tendermint_proto::serializers::from_str")] + #[serde(with = "serializers::from_str")] pub height: i64, pub index: Option, - #[serde(with = "tendermint_proto::serializers::bytes::base64string")] + #[serde(with = "serializers::bytes::base64string")] pub tx: Vec, pub result: TxResult, } diff --git a/rpc/src/query.rs b/rpc/src/query.rs index 1576c0702..0774a81f2 100644 --- a/rpc/src/query.rs +++ b/rpc/src/query.rs @@ -6,14 +6,13 @@ use core::{fmt, str::FromStr}; -use tendermint_proto::serializers::timestamp; use time::{ format_description::well_known::Rfc3339, macros::{format_description, offset}, Date, OffsetDateTime, }; -use crate::{prelude::*, Error}; +use crate::{prelude::*, serializers::timestamp, Error}; /// A structured query for use in interacting with the Tendermint RPC event /// subscription system. diff --git a/rpc/src/serializers.rs b/rpc/src/serializers.rs index d55dff33b..dd8ae81b4 100644 --- a/rpc/src/serializers.rs +++ b/rpc/src/serializers.rs @@ -5,7 +5,7 @@ //! CAUTION: There are no guarantees for backwards compatibility, this module should be considered //! an internal implementation detail which can vanish without further warning. Use at your own //! risk. -pub use tendermint_proto::serializers::*; +pub use tendermint::serializers::*; pub mod opt_tm_hash_base64; pub mod tm_hash_base64; From 718cd4ea8197e8c4ec51504d8cf2d4e84f310cf3 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Wed, 16 Nov 2022 16:59:24 +0200 Subject: [PATCH 2/8] Rename merkle::Proof to merkle::ProofOps The protobuf message name is actually ProofOps, and the crypto package also defines Proof, for which we now want to have a domain type. --- rpc/src/endpoint/abci_query.rs | 4 ++-- tendermint/src/abci/response/query.rs | 2 +- tendermint/src/merkle/proof.rs | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rpc/src/endpoint/abci_query.rs b/rpc/src/endpoint/abci_query.rs index ff1eed266..7ed6cc464 100644 --- a/rpc/src/endpoint/abci_query.rs +++ b/rpc/src/endpoint/abci_query.rs @@ -1,7 +1,7 @@ //! `/abci_query` endpoint JSON-RPC wrapper use serde::{Deserialize, Serialize}; -use tendermint::{abci::Code, block, merkle::proof::Proof, serializers}; +use tendermint::{abci::Code, block, merkle::proof::ProofOps, serializers}; use crate::prelude::*; @@ -87,7 +87,7 @@ pub struct AbciQuery { /// Proof (might be explicit null) #[serde(alias = "proofOps")] - pub proof: Option, + pub proof: Option, /// Block height pub height: block::Height, diff --git a/tendermint/src/abci/response/query.rs b/tendermint/src/abci/response/query.rs index 3a667ff01..40fbc8beb 100644 --- a/tendermint/src/abci/response/query.rs +++ b/tendermint/src/abci/response/query.rs @@ -25,7 +25,7 @@ pub struct Query { pub value: Bytes, /// Serialized proof for the value data, if requested, to be verified against /// the app hash for the given `height`. - pub proof: Option, + pub proof: Option, /// The block height from which data was derived. /// /// Note that this is the height of the block containing the application's diff --git a/tendermint/src/merkle/proof.rs b/tendermint/src/merkle/proof.rs index 0e79c35a8..93fc17295 100644 --- a/tendermint/src/merkle/proof.rs +++ b/tendermint/src/merkle/proof.rs @@ -9,10 +9,10 @@ use tendermint_proto::{ use crate::{prelude::*, serializers, Error}; -/// Proof is Merkle proof defined by the list of ProofOps +/// Merkle proof defined by the list of ProofOps /// #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct Proof { +pub struct ProofOps { /// The list of ProofOps pub ops: Vec, } @@ -58,9 +58,9 @@ impl From for RawProofOp { } } -impl Protobuf for Proof {} +impl Protobuf for ProofOps {} -impl TryFrom for Proof { +impl TryFrom for ProofOps { type Error = Error; fn try_from(value: RawProofOps) -> Result { @@ -70,8 +70,8 @@ impl TryFrom for Proof { } } -impl From for RawProofOps { - fn from(value: Proof) -> Self { +impl From for RawProofOps { + fn from(value: ProofOps) -> Self { let ops: Vec = value.ops.into_iter().map(RawProofOp::from).collect(); RawProofOps { ops } @@ -80,7 +80,7 @@ impl From for RawProofOps { #[cfg(test)] mod test { - use super::Proof; + use super::ProofOps; use crate::test::test_serialization_roundtrip; #[test] @@ -100,6 +100,6 @@ mod test { } ] }"#; - test_serialization_roundtrip::(payload); + test_serialization_roundtrip::(payload); } } From f67684a51d61e3722728ff0b1187698d0b772b36 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Wed, 16 Nov 2022 20:42:52 +0200 Subject: [PATCH 3/8] tendermint: add domain type merkle::Proof Corresponds to the protobuf message crypto.Proof. --- tendermint/src/error.rs | 8 +++++ tendermint/src/merkle.rs | 2 ++ tendermint/src/merkle/proof.rs | 56 ++++++++++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/tendermint/src/error.rs b/tendermint/src/error.rs index 2d6e6cf80..0e01e2c9a 100644 --- a/tendermint/src/error.rs +++ b/tendermint/src/error.rs @@ -220,6 +220,14 @@ define_error! { TrustThresholdTooSmall |_| { "trust threshold too small (must be >= 1/3)" }, + + NegativeProofTotal + [ DisplayOnly ] + |_| { "negative number of items in proof" }, + + NegativeProofIndex + [ DisplayOnly ] + |_| { "negative item index in proof" }, } } diff --git a/tendermint/src/merkle.rs b/tendermint/src/merkle.rs index e57979bf3..23f0df8fd 100644 --- a/tendermint/src/merkle.rs +++ b/tendermint/src/merkle.rs @@ -2,6 +2,8 @@ pub mod proof; +pub use proof::Proof; + use sha2::{Digest, Sha256}; use crate::prelude::*; diff --git a/tendermint/src/merkle/proof.rs b/tendermint/src/merkle/proof.rs index 93fc17295..df5ad2bdd 100644 --- a/tendermint/src/merkle/proof.rs +++ b/tendermint/src/merkle/proof.rs @@ -3,11 +3,24 @@ use core::convert::TryFrom; use serde::{Deserialize, Serialize}; use tendermint_proto::{ - crypto::{ProofOp as RawProofOp, ProofOps as RawProofOps}, + crypto::{Proof as RawProof, ProofOp as RawProofOp, ProofOps as RawProofOps}, Protobuf, }; -use crate::{prelude::*, serializers, Error}; +use crate::{prelude::*, serializers, Error, Hash}; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(try_from = "RawProof", into = "RawProof")] +pub struct Proof { + // Total number of items. + pub total: u64, + // Index of the item to prove. + pub index: u64, + // Hash of item value. + pub leaf_hash: Hash, + // Hashes from leaf's sibling to a root's child. + pub aunts: Vec, +} /// Merkle proof defined by the list of ProofOps /// @@ -34,6 +47,45 @@ 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::>()?, + }) + } +} + +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 TryFrom for ProofOp { From 00fbf086c40591c8de568405d72a2fe6a9b8249d Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Wed, 16 Nov 2022 21:07:58 +0200 Subject: [PATCH 4/8] tendermint: mod tx and domain type tx::Proof Corresponds to protobuf types.TxProof --- tendermint/src/lib.rs | 1 + tendermint/src/tx.rs | 3 +++ tendermint/src/tx/proof.rs | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tendermint/src/tx.rs create mode 100644 tendermint/src/tx/proof.rs diff --git a/tendermint/src/lib.rs b/tendermint/src/lib.rs index a055afac9..74a554014 100644 --- a/tendermint/src/lib.rs +++ b/tendermint/src/lib.rs @@ -48,6 +48,7 @@ pub mod signature; pub mod time; mod timeout; pub mod trust_threshold; +pub mod tx; pub mod validator; mod version; pub mod vote; diff --git a/tendermint/src/tx.rs b/tendermint/src/tx.rs new file mode 100644 index 000000000..92cb4ffcb --- /dev/null +++ b/tendermint/src/tx.rs @@ -0,0 +1,3 @@ +mod proof; + +pub use proof::Proof; diff --git a/tendermint/src/tx/proof.rs b/tendermint/src/tx/proof.rs new file mode 100644 index 000000000..c29b6dbbe --- /dev/null +++ b/tendermint/src/tx/proof.rs @@ -0,0 +1,37 @@ +use serde::{Deserialize, Serialize}; +use tendermint_proto::types::TxProof as RawTxProof; +use tendermint_proto::Protobuf; + +use crate::{merkle, prelude::*, Error, Hash}; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(try_from = "RawTxProof", into = "RawTxProof")] +pub struct Proof { + pub root_hash: Hash, + pub data: Vec, + pub proof: merkle::Proof, +} + +impl Protobuf for Proof {} + +impl TryFrom for Proof { + type Error = Error; + + fn try_from(message: RawTxProof) -> Result { + Ok(Self { + root_hash: message.root_hash.try_into()?, + data: message.data, + proof: message.proof.ok_or_else(Error::missing_data)?.try_into()?, + }) + } +} + +impl From for RawTxProof { + fn from(value: Proof) -> Self { + Self { + root_hash: value.root_hash.into(), + data: value.data, + proof: Some(value.proof.into()), + } + } +} From bd68333851fe4ddd5cda128ec1beb574cf9a7f58 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Wed, 16 Nov 2022 21:09:28 +0200 Subject: [PATCH 5/8] rpc: Change /tx response field type to tx::Proof Thus removing the last direct use of tendermint_proto. --- rpc/src/endpoint/tx.rs | 5 ++--- rpc/tests/kvstore_fixtures.rs | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rpc/src/endpoint/tx.rs b/rpc/src/endpoint/tx.rs index 4fd0aa27a..fed4ae85b 100644 --- a/rpc/src/endpoint/tx.rs +++ b/rpc/src/endpoint/tx.rs @@ -1,8 +1,7 @@ //! `/tx` endpoint JSON-RPC wrapper use serde::{Deserialize, Serialize}; -use tendermint::{abci, block, Hash}; -use tendermint_proto::types::TxProof; +use tendermint::{abci, block, tx, Hash}; use crate::{prelude::*, serializers, Method}; @@ -51,7 +50,7 @@ pub struct Response { #[serde(with = "serializers::bytes::base64string")] pub tx: Vec, #[serde(skip_serializing_if = "Option::is_none")] - pub proof: Option, + pub proof: Option, } impl crate::Response for Response {} diff --git a/rpc/tests/kvstore_fixtures.rs b/rpc/tests/kvstore_fixtures.rs index 5a6bde9bb..53223b7fb 100644 --- a/rpc/tests/kvstore_fixtures.rs +++ b/rpc/tests/kvstore_fixtures.rs @@ -1393,8 +1393,9 @@ fn incoming_fixtures() { assert!(tx.tx_result.log.is_empty()); let proof = tx.proof.unwrap(); assert_eq!(proof.data, tx.tx); - assert!(proof.proof.is_some()); - assert_ne!(proof.root_hash, [0; 32]); + assert_eq!(proof.proof.total, 1); + assert_eq!(proof.proof.index, 0); + assert_ne!(proof.root_hash.as_bytes(), [0; 32]); } }, _ => { From c3d1eef42ff189872633dd59b2fc40b48f55df23 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Wed, 16 Nov 2022 21:09:55 +0200 Subject: [PATCH 6/8] rpc: remove dependency on tendermint-proto --- rpc/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index ed47472cf..9af4ffb0e 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -71,7 +71,6 @@ serde_bytes = { version = "0.11", default-features = false } serde_json = { version = "1", default-features = false, features = ["std"] } tendermint-config = { version = "0.26.0", path = "../config", default-features = false } tendermint = { version = "0.26.0", default-features = false, path = "../tendermint" } -tendermint-proto = { version = "0.26.0", default-features = false, path = "../proto" } thiserror = { version = "1", default-features = false } time = { version = "0.3", default-features = false, features = ["macros", "parsing"] } uuid = { version = "0.8", default-features = false } From 18a563fe4ab22de9261fa0e35bc6980e07cba95d Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Wed, 16 Nov 2022 21:35:55 +0200 Subject: [PATCH 7/8] tendermint: slap some doc on tx::Proof --- tendermint/src/tx/proof.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tendermint/src/tx/proof.rs b/tendermint/src/tx/proof.rs index c29b6dbbe..7d8abfa7a 100644 --- a/tendermint/src/tx/proof.rs +++ b/tendermint/src/tx/proof.rs @@ -4,6 +4,7 @@ use tendermint_proto::Protobuf; use crate::{merkle, prelude::*, Error, Hash}; +/// Merkle proof of the presence of a transaction in the Merkle tree. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "RawTxProof", into = "RawTxProof")] pub struct Proof { From 1d1b8109a41020d4e266f3f654a71e32a4784e1d Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Wed, 16 Nov 2022 21:48:14 +0200 Subject: [PATCH 8/8] Changelog entries for #1234 --- .../breaking-changes/1234-decouple-rpc-from-proto.md | 5 +++++ .../unreleased/improvements/1234-decouple-rpc-from-proto.md | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 .changelog/unreleased/breaking-changes/1234-decouple-rpc-from-proto.md create mode 100644 .changelog/unreleased/improvements/1234-decouple-rpc-from-proto.md diff --git a/.changelog/unreleased/breaking-changes/1234-decouple-rpc-from-proto.md b/.changelog/unreleased/breaking-changes/1234-decouple-rpc-from-proto.md new file mode 100644 index 000000000..4f584c3fa --- /dev/null +++ b/.changelog/unreleased/breaking-changes/1234-decouple-rpc-from-proto.md @@ -0,0 +1,5 @@ +- `[tendermint]` Rename `merkle::proof::Proof` to `ProofOps` + ([#1234](https://github.com/informalsystems/tendermint-rs/pull/1234)) +- `[tendermint-rpc]` Change the type of `/tx` response field `proof` + to `tendermint::tx::Proof` + ([#1233](https://github.com/informalsystems/tendermint-rs/issues/1233)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/1234-decouple-rpc-from-proto.md b/.changelog/unreleased/improvements/1234-decouple-rpc-from-proto.md new file mode 100644 index 000000000..fe56cb92d --- /dev/null +++ b/.changelog/unreleased/improvements/1234-decouple-rpc-from-proto.md @@ -0,0 +1,3 @@ +- `[tendermint]` Add domain types `merkle::Proof` and `tx::Proof`, + to represent protobuf messages `crypto.Proof` and `types.TxProof` respectively + ([#1234](https://github.com/informalsystems/tendermint-rs/pull/1234))