From 9c431c6f1fb1a22e1e3f63bec46707fff05ba782 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 20 Sep 2021 12:13:52 +0200 Subject: [PATCH 01/16] Move out tendermint::config to tendermint_config crate --- Cargo.toml | 1 + config/Cargo.toml | 42 +++ {tendermint => config}/src/config.rs | 7 +- config/src/lib.rs | 5 + .../src/config => config/src}/node_key.rs | 3 +- .../src}/priv_validator_key.rs | 4 +- {tendermint => config}/tests/config.rs | 3 +- config/tests/mod.rs | 239 ++++++++++++++++++ .../TestDeriveSecretsAndChallenge.golden | 0 .../tests/support/config/config.toml | 0 .../tests/support/config/node_key.json | 0 .../support/config/priv_validator_key.json | 0 light-client/src/components/verifier.rs | 10 +- light-client/tests/model_based.rs | 4 +- tendermint/src/lib.rs | 2 +- 15 files changed, 302 insertions(+), 18 deletions(-) create mode 100644 config/Cargo.toml rename {tendermint => config}/src/config.rs (99%) create mode 100644 config/src/lib.rs rename {tendermint/src/config => config/src}/node_key.rs (91%) rename {tendermint/src/config => config/src}/priv_validator_key.rs (91%) rename {tendermint => config}/tests/config.rs (99%) create mode 100644 config/tests/mod.rs rename {tendermint => config}/tests/support/TestDeriveSecretsAndChallenge.golden (100%) rename {tendermint => config}/tests/support/config/config.toml (100%) rename {tendermint => config}/tests/support/config/node_key.json (100%) rename {tendermint => config}/tests/support/config/priv_validator_key.json (100%) diff --git a/Cargo.toml b/Cargo.toml index 4a3a782c9..6411b720b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "abci", + "config", "light-client", "light-client-js", "p2p", diff --git a/config/Cargo.toml b/config/Cargo.toml new file mode 100644 index 000000000..6e5bd2752 --- /dev/null +++ b/config/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "tendermint-config" +version = "0.21.0" # Also update `html_root_url` in lib.rs and + # depending crates (rpc, light-node, ..) when bumping this +license = "Apache-2.0" +homepage = "https://www.tendermint.com/" +repository = "https://github.com/informalsystems/tendermint-rs/tree/master/tendermint" +readme = "../README.md" +categories = ["cryptography", "cryptography::cryptocurrencies", "database"] +keywords = ["blockchain", "bft", "consensus", "cosmos", "tendermint"] +edition = "2018" + +description = """ + Tendermint is a high-performance blockchain consensus engine that powers + Byzantine fault tolerant applications written in any programming language. + This crate provides core types for representing information about Tendermint + blockchain networks, including chain information types, secret connections, + and remote procedure calls (JSON-RPC). + """ + +authors = [ + "Informal Systems ", + "Ismail Khoffi ", + "ValarDragon ", + "Tony Arcieri ", +] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +tendermint = { version = "0.21.0", default-features = false, path = "../tendermint" } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +toml = { version = "0.5" } + +[dev-dependencies] +pretty_assertions = "0.7.2" diff --git a/tendermint/src/config.rs b/config/src/config.rs similarity index 99% rename from tendermint/src/config.rs rename to config/src/config.rs index bf5e59bb2..e1d6a58a6 100644 --- a/tendermint/src/config.rs +++ b/config/src/config.rs @@ -6,12 +6,8 @@ //! - `node_key.rs`: `config::node_key::NodeKey` //! - `priv_validator_key.rs`: `config::priv_validator_key::PrivValidatorKey` -mod node_key; -mod priv_validator_key; +pub use crate::{node_key::NodeKey, priv_validator_key::PrivValidatorKey}; -pub use self::{node_key::NodeKey, priv_validator_key::PrivValidatorKey}; - -use crate::{error::Error, genesis::Genesis, net, node, Moniker, Timeout}; use serde::{de, de::Error as _, ser, Deserialize, Serialize}; use std::{ collections::BTreeMap, @@ -19,6 +15,7 @@ use std::{ path::{Path, PathBuf}, str::FromStr, }; +use tendermint::{error::Error, genesis::Genesis, net, node, Moniker, Timeout}; /// Tendermint `config.toml` file #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] diff --git a/config/src/lib.rs b/config/src/lib.rs new file mode 100644 index 000000000..c71970f6a --- /dev/null +++ b/config/src/lib.rs @@ -0,0 +1,5 @@ +mod config; +mod node_key; +mod priv_validator_key; + +pub use config::*; diff --git a/tendermint/src/config/node_key.rs b/config/src/node_key.rs similarity index 91% rename from tendermint/src/config/node_key.rs rename to config/src/node_key.rs index e1abe7e4a..33dc5b067 100644 --- a/tendermint/src/config/node_key.rs +++ b/config/src/node_key.rs @@ -1,8 +1,8 @@ //! Node keys -use crate::{error::Error, node, private_key::PrivateKey, public_key::PublicKey}; use serde::{Deserialize, Serialize}; use std::{fs, path::Path}; +use tendermint::{error::Error, node, private_key::PrivateKey, public_key::PublicKey}; /// P2P node private keys #[derive(Serialize, Deserialize)] @@ -33,6 +33,7 @@ impl NodeKey { pub fn public_key(&self) -> PublicKey { match &self.priv_key { PrivateKey::Ed25519(keypair) => keypair.public.into(), + _ => todo!(), } } diff --git a/tendermint/src/config/priv_validator_key.rs b/config/src/priv_validator_key.rs similarity index 91% rename from tendermint/src/config/priv_validator_key.rs rename to config/src/priv_validator_key.rs index f6f3d7bc4..c97233660 100644 --- a/tendermint/src/config/priv_validator_key.rs +++ b/config/src/priv_validator_key.rs @@ -1,9 +1,9 @@ //! Validator private keys -use crate::public_key::TendermintKey; -use crate::{account, error::Error, private_key::PrivateKey, public_key::PublicKey}; use serde::{Deserialize, Serialize}; use std::{fs, path::Path}; +use tendermint::public_key::TendermintKey; +use tendermint::{account, error::Error, private_key::PrivateKey, public_key::PublicKey}; /// Validator private key #[derive(Serialize, Deserialize)] // JSON custom serialization for priv_validator_key.json diff --git a/tendermint/tests/config.rs b/config/tests/config.rs similarity index 99% rename from tendermint/tests/config.rs rename to config/tests/config.rs index 60d947a74..13bcef4da 100644 --- a/tendermint/tests/config.rs +++ b/config/tests/config.rs @@ -6,7 +6,8 @@ mod files { #[cfg(test)] use pretty_assertions::assert_eq; use std::{fs, path::PathBuf, time::Duration}; - use tendermint::{config::*, net, node}; + use tendermint::{net, node}; + use tendermint_config::*; /// Read a fixture file from the `support/config` directory fn read_fixture(name: &str) -> String { diff --git a/config/tests/mod.rs b/config/tests/mod.rs new file mode 100644 index 000000000..13bcef4da --- /dev/null +++ b/config/tests/mod.rs @@ -0,0 +1,239 @@ +//! Tests for parsing configuration files. +//! +//! Test config files are located in the `tests/support/config` subdirectory. + +mod files { + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::{fs, path::PathBuf, time::Duration}; + use tendermint::{net, node}; + use tendermint_config::*; + + /// Read a fixture file from the `support/config` directory + fn read_fixture(name: &str) -> String { + fs::read_to_string(PathBuf::from("./tests/support/config/").join(name)).unwrap() + } + + /// Parse an example `config.toml` file to a `TendermintConfig` struct + #[allow(clippy::cognitive_complexity)] + #[test] + fn config_toml_parser() { + let config_toml = read_fixture("config.toml"); + let config = TendermintConfig::parse_toml(&config_toml).unwrap(); + + // main base config options + + assert_eq!( + config.proxy_app, + "tcp://127.0.0.1:26658".parse::().unwrap() + ); + assert_eq!(config.moniker.as_ref(), "technodrome"); + assert!(config.fast_sync); + assert_eq!(config.db_backend, DbBackend::GoLevelDb); + assert_eq!(config.db_dir, PathBuf::from("data")); + assert_eq!(config.log_level.global, Some("info".to_string())); + assert_eq!(config.log_level.get("main"), Some("info")); + assert_eq!(config.log_level.get("state"), Some("info")); + assert_eq!(config.log_level.get("*"), Some("info")); + assert_eq!(config.log_format, LogFormat::Plain); + assert_eq!(config.genesis_file, PathBuf::from("config/genesis.json")); + assert_eq!( + config.priv_validator_key_file, + Some(PathBuf::from("config/priv_validator_key.json")) + ); + assert_eq!( + config.priv_validator_state_file, + PathBuf::from("data/priv_validator_state.json") + ); + assert_eq!(config.priv_validator_laddr, None); + assert_eq!(config.node_key_file, PathBuf::from("config/node_key.json")); + assert_eq!(config.abci, AbciMode::Socket); + assert!(!config.filter_peers); + + // rpc server configuration options + + let rpc = &config.rpc; + assert_eq!( + rpc.laddr, + "tcp://0.0.0.0:26657".parse::().unwrap() + ); + assert!(rpc.cors_allowed_origins.is_empty()); + assert_eq!(rpc.cors_allowed_methods.len(), 3); + assert_eq!(rpc.cors_allowed_methods[0].as_ref(), "HEAD"); + assert_eq!(rpc.cors_allowed_methods[1].as_ref(), "GET"); + assert_eq!(rpc.cors_allowed_methods[2].as_ref(), "POST"); + assert_eq!(rpc.cors_allowed_headers.len(), 5); + assert_eq!(rpc.cors_allowed_headers[0].as_ref(), "Origin"); + assert_eq!(rpc.cors_allowed_headers[1].as_ref(), "Accept"); + assert_eq!(rpc.cors_allowed_headers[2].as_ref(), "Content-Type"); + assert_eq!(rpc.cors_allowed_headers[3].as_ref(), "X-Requested-With"); + assert_eq!(rpc.cors_allowed_headers[4].as_ref(), "X-Server-Time"); + assert_eq!(rpc.grpc_laddr, None); + assert_eq!(rpc.grpc_max_open_connections, 900); + assert!(!rpc.unsafe_commands); + assert_eq!(rpc.max_open_connections, 900); + assert_eq!(rpc.max_subscription_clients, 100); + assert_eq!(rpc.max_subscriptions_per_client, 5); + assert_eq!(*rpc.timeout_broadcast_tx_commit, Duration::from_secs(10)); + assert_eq!(rpc.tls_cert_file, None); + assert_eq!(rpc.tls_key_file, None); + + // peer to peer configuration options + + let p2p = &config.p2p; + assert_eq!( + p2p.laddr, + "tcp://0.0.0.0:26656".parse::().unwrap() + ); + assert_eq!(p2p.external_address, None); + assert_eq!(p2p.seeds.len(), 2); + assert_eq!( + p2p.seeds[0], + "tcp://c2e1bde78877975b31e6f06e77da200a38048e2b@seed-1.example.com:26656" + .parse::() + .unwrap() + ); + assert_eq!( + p2p.seeds[1], + "tcp://0eafed3e9e76f626a299e1b8a79454fffe9ca83c@seed-2.example.com:26656" + .parse::() + .unwrap() + ); + assert_eq!(p2p.persistent_peers.len(), 2); + assert_eq!( + p2p.persistent_peers[0], + "tcp://70d834561f91613153e4a873f01a2cbbf1b9678d@1.2.3.4:26656" + .parse::() + .unwrap() + ); + assert_eq!( + p2p.persistent_peers[1], + "tcp://f68ed33a0baa0c734a939a9e60659566adc725cd@peer-2.example.com:26656" + .parse::() + .unwrap() + ); + assert!(!p2p.upnp); + assert_eq!(p2p.addr_book_file, PathBuf::from("config/addrbook.json")); + assert!(p2p.addr_book_strict); + assert_eq!(p2p.max_num_inbound_peers, 40); + assert_eq!(p2p.max_num_outbound_peers, 10); + assert_eq!(*p2p.flush_throttle_timeout, Duration::from_millis(100)); + assert_eq!(p2p.max_packet_msg_payload_size, 1024); + assert_eq!(p2p.send_rate.bytes_per_sec(), 5_120_000); + assert_eq!(p2p.recv_rate.bytes_per_sec(), 5_120_000); + assert!(p2p.pex); + assert!(!p2p.seed_mode); + assert_eq!(p2p.private_peer_ids.len(), 3); + assert_eq!( + p2p.private_peer_ids[0], + "8112E5C5AB6A48ADCC0E875D58A4264A2639F6A8" + .parse::() + .unwrap() + ); + assert_eq!( + p2p.private_peer_ids[1], + "3D1B9086E48C7BDF7F0D766351EED812A75DE500" + .parse::() + .unwrap() + ); + assert_eq!( + p2p.private_peer_ids[2], + "A7306AEE50627E68177A002BADD3BA4A45301AD4" + .parse::() + .unwrap() + ); + assert!(!p2p.allow_duplicate_ip); + assert_eq!(*p2p.handshake_timeout, Duration::from_secs(20)); + assert_eq!(*p2p.dial_timeout, Duration::from_secs(3)); + + // mempool configuration options + + let mempool = &config.mempool; + assert!(mempool.recheck); + assert!(mempool.broadcast); + assert_eq!(mempool.wal_dir, None); + assert_eq!(mempool.size, 5000); + assert_eq!(mempool.max_txs_bytes, 1_073_741_824); + assert_eq!(mempool.cache_size, 10000); + + // consensus configuration options + + let consensus = &config.consensus; + assert_eq!(consensus.wal_file, PathBuf::from("data/cs.wal/wal")); + assert_eq!(*consensus.timeout_propose, Duration::from_secs(3)); + assert_eq!(*consensus.timeout_propose_delta, Duration::from_millis(500)); + assert_eq!(*consensus.timeout_prevote, Duration::from_secs(1)); + assert_eq!(*consensus.timeout_prevote_delta, Duration::from_millis(500)); + assert_eq!(*consensus.timeout_precommit, Duration::from_secs(1)); + assert_eq!( + *consensus.timeout_precommit_delta, + Duration::from_millis(500) + ); + assert_eq!(*consensus.timeout_commit, Duration::from_secs(5)); + assert!(!consensus.skip_timeout_commit); + assert_eq!( + *consensus.create_empty_blocks_interval, + Duration::from_secs(0) + ); + assert_eq!( + *consensus.peer_gossip_sleep_duration, + Duration::from_millis(100) + ); + assert_eq!( + *consensus.peer_query_maj23_sleep_duration, + Duration::from_secs(2) + ); + + // transactions indexer configuration options + + let tx_index = &config.tx_index; + assert_eq!(tx_index.indexer, TxIndexer::Kv); + + // instrumentation configuration options + + let instrumentation = &config.instrumentation; + assert!(!instrumentation.prometheus); + assert_eq!(instrumentation.prometheus_listen_addr, ":26660"); + assert_eq!(instrumentation.max_open_connections, 3); + assert_eq!(instrumentation.namespace, "tendermint"); + } + + /// Parse an example `node_key.json` file to a `NodeKey` struct + #[test] + fn node_key_parser() { + let raw_node_key = read_fixture("node_key.json"); + let node_key = NodeKey::parse_json(&raw_node_key).unwrap(); + assert_eq!( + node_key.node_id().to_string(), + "1A7B6BCF3D6FB055AB3AEBCA415847531B626699" + ); + } + + /// Parse an example `priv_validator_key.json` to a `PrivValidatorKey` struct + #[test] + fn priv_validator_json_parser() { + let raw_priv_validator_key = read_fixture("priv_validator_key.json"); + let priv_validator_key = PrivValidatorKey::parse_json(&raw_priv_validator_key).unwrap(); + assert_eq!( + priv_validator_key.consensus_pubkey().to_hex(), + "F26BF4B2A2E84CEB7A53C3F1AE77408779B20064782FBADBDF0E365959EE4534" + ); + } + + /// Parse an example `config.toml` file to a `TendermintConfig` struct, then + /// serialize it and parse again. + #[test] + fn parsing_roundtrip() { + let config_toml = read_fixture("config.toml"); + let config = TendermintConfig::parse_toml(&config_toml).unwrap(); + + let written_config_toml = toml::to_string(&config).unwrap(); + let written_config = TendermintConfig::parse_toml(&written_config_toml).unwrap(); + + assert_eq!( + config, written_config, + "written config {}", + written_config_toml + ); + } +} diff --git a/tendermint/tests/support/TestDeriveSecretsAndChallenge.golden b/config/tests/support/TestDeriveSecretsAndChallenge.golden similarity index 100% rename from tendermint/tests/support/TestDeriveSecretsAndChallenge.golden rename to config/tests/support/TestDeriveSecretsAndChallenge.golden diff --git a/tendermint/tests/support/config/config.toml b/config/tests/support/config/config.toml similarity index 100% rename from tendermint/tests/support/config/config.toml rename to config/tests/support/config/config.toml diff --git a/tendermint/tests/support/config/node_key.json b/config/tests/support/config/node_key.json similarity index 100% rename from tendermint/tests/support/config/node_key.json rename to config/tests/support/config/node_key.json diff --git a/tendermint/tests/support/config/priv_validator_key.json b/config/tests/support/config/priv_validator_key.json similarity index 100% rename from tendermint/tests/support/config/priv_validator_key.json rename to config/tests/support/config/priv_validator_key.json diff --git a/light-client/src/components/verifier.rs b/light-client/src/components/verifier.rs index a800296e7..5bf03bc54 100644 --- a/light-client/src/components/verifier.rs +++ b/light-client/src/components/verifier.rs @@ -128,14 +128,12 @@ where /// /// - Ensure the latest trusted header hasn't expired /// - Ensure the header validator hashes match the given validators - /// - Ensure the header next validator hashes match the given next - /// validators + /// - Ensure the header next validator hashes match the given next validators /// - Additional implementation specific validation via `commit_validator` /// - Check that the untrusted block is more recent than the trusted state - /// - If the untrusted block is the very next block after the trusted block, - /// check that their (next) validator sets hashes match. - /// - Otherwise, ensure that the untrusted block has a greater height than - /// the trusted block. + /// - If the untrusted block is the very next block after the trusted block, check that their + /// (next) validator sets hashes match. + /// - Otherwise, ensure that the untrusted block has a greater height than the trusted block. /// /// **NOTE**: If the untrusted state's `next_validators` field is `None`, /// this will not (and will not be able to) check whether the untrusted diff --git a/light-client/tests/model_based.rs b/light-client/tests/model_based.rs index 48a883136..9ceba88e3 100644 --- a/light-client/tests/model_based.rs +++ b/light-client/tests/model_based.rs @@ -125,8 +125,8 @@ mod mbt { impl SingleStepTestFuzzer for HeaderVersionFuzzer { // TODO: rehash the header and re-compute commit with it // TODO: Unlike in tendermint-go, we don't assert for a particular version in rust - // TODO: Either add this check in verification or remove this test because otherwise there's no - // point of it + // TODO: Either add this check in verification or remove this test because otherwise there's + // no point of it fn fuzz_input(input: &mut BlockVerdict) -> (String, LiteVerdict) { let mut rng = rand::thread_rng(); diff --git a/tendermint/src/lib.rs b/tendermint/src/lib.rs index aed2bd270..f74b9df96 100644 --- a/tendermint/src/lib.rs +++ b/tendermint/src/lib.rs @@ -5,6 +5,7 @@ //! and remote procedure calls (JSON-RPC). #![cfg_attr(docsrs, feature(doc_cfg))] +#![allow(dead_code)] #![deny( warnings, trivial_casts, @@ -28,7 +29,6 @@ pub mod account; pub mod block; pub mod chain; pub mod channel; -pub mod config; pub mod consensus; pub mod evidence; pub mod genesis; From 07a698af7b6b697c6fa0f4296a46577522f26521 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 20 Sep 2021 12:45:22 +0200 Subject: [PATCH 02/16] Introduce own error type in tendermint-config --- config/Cargo.toml | 8 ++++++++ config/src/config.rs | 5 +++-- config/src/error.rs | 33 ++++++++++++++++++++++++++++++++ config/src/lib.rs | 4 ++++ config/src/node_key.rs | 4 +++- config/src/priv_validator_key.rs | 7 +++++-- tendermint/Cargo.toml | 1 - tendermint/src/error.rs | 18 ----------------- 8 files changed, 56 insertions(+), 24 deletions(-) create mode 100644 config/src/error.rs diff --git a/config/Cargo.toml b/config/Cargo.toml index 6e5bd2752..a561b0ddb 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -34,9 +34,17 @@ crate-type = ["cdylib", "rlib"] [dependencies] tendermint = { version = "0.21.0", default-features = false, path = "../tendermint" } +flex-error = { version = "0.4.1", default-features = false } serde = { version = "1", features = ["derive"] } serde_json = "1" toml = { version = "0.5" } [dev-dependencies] pretty_assertions = "0.7.2" + +[features] +default = ["std", "eyre_tracer"] +eyre_tracer = ["flex-error/eyre_tracer"] +std = [ + "flex-error/std" +] diff --git a/config/src/config.rs b/config/src/config.rs index e1d6a58a6..a27e29391 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -6,7 +6,8 @@ //! - `node_key.rs`: `config::node_key::NodeKey` //! - `priv_validator_key.rs`: `config::priv_validator_key::PrivValidatorKey` -pub use crate::{node_key::NodeKey, priv_validator_key::PrivValidatorKey}; +use crate::node_key::NodeKey; +use crate::Error; use serde::{de, de::Error as _, ser, Deserialize, Serialize}; use std::{ @@ -15,7 +16,7 @@ use std::{ path::{Path, PathBuf}, str::FromStr, }; -use tendermint::{error::Error, genesis::Genesis, net, node, Moniker, Timeout}; +use tendermint::{genesis::Genesis, net, node, Moniker, Timeout}; /// Tendermint `config.toml` file #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] diff --git a/config/src/error.rs b/config/src/error.rs new file mode 100644 index 000000000..1cafdcfd3 --- /dev/null +++ b/config/src/error.rs @@ -0,0 +1,33 @@ +use flex_error::{define_error, DisplayOnly}; +use std::io::Error as IoError; +use tendermint::Error as TendermintError; + +define_error! { + #[derive(Debug, Clone, PartialEq, Eq)] + Error { + Io + [ DisplayOnly ] + |_| { format_args!("I/O error") }, + + FileIo + { path: String } + [ DisplayOnly ] + |e| { format_args!("failed to open file: {}", e.path) }, + + Parse + { data: String } + | e | { format_args!("error parsing data: {}", e.data) }, + + SerdeJson + [ DisplayOnly ] + |_| { format_args!("serde json error") }, + + Toml + [ DisplayOnly ] + |_| { format_args!("toml de error") }, + + Tendermint + [ TendermintError ] + |_| { format_args!("tendermint error") }, + } +} diff --git a/config/src/lib.rs b/config/src/lib.rs index c71970f6a..856195ddd 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -1,5 +1,9 @@ mod config; +mod error; mod node_key; mod priv_validator_key; pub use config::*; +pub use error::*; +pub use node_key::NodeKey; +pub use priv_validator_key::PrivValidatorKey; diff --git a/config/src/node_key.rs b/config/src/node_key.rs index 33dc5b067..61543cf4a 100644 --- a/config/src/node_key.rs +++ b/config/src/node_key.rs @@ -2,7 +2,9 @@ use serde::{Deserialize, Serialize}; use std::{fs, path::Path}; -use tendermint::{error::Error, node, private_key::PrivateKey, public_key::PublicKey}; +use tendermint::{node, private_key::PrivateKey, public_key::PublicKey}; + +use crate::error::Error; /// P2P node private keys #[derive(Serialize, Deserialize)] diff --git a/config/src/priv_validator_key.rs b/config/src/priv_validator_key.rs index c97233660..6dcc2508d 100644 --- a/config/src/priv_validator_key.rs +++ b/config/src/priv_validator_key.rs @@ -3,7 +3,9 @@ use serde::{Deserialize, Serialize}; use std::{fs, path::Path}; use tendermint::public_key::TendermintKey; -use tendermint::{account, error::Error, private_key::PrivateKey, public_key::PublicKey}; +use tendermint::{account, private_key::PrivateKey, public_key::PublicKey}; + +use crate::error::Error; /// Validator private key #[derive(Serialize, Deserialize)] // JSON custom serialization for priv_validator_key.json @@ -25,7 +27,8 @@ impl PrivValidatorKey { serde_json::from_str::(json_string.as_ref()).map_err(Error::serde_json)?; // Validate that the parsed key type is usable as a consensus key - TendermintKey::new_consensus_key(result.priv_key.public_key())?; + TendermintKey::new_consensus_key(result.priv_key.public_key()) + .map_err(Error::tendermint)?; Ok(result) } diff --git a/tendermint/Cargo.toml b/tendermint/Cargo.toml index bbb4b5991..3424eb8c4 100644 --- a/tendermint/Cargo.toml +++ b/tendermint/Cargo.toml @@ -52,7 +52,6 @@ signature = "1.2" subtle = "2" subtle-encoding = { version = "0.5", features = ["bech32-preview"] } tendermint-proto = { version = "0.21.0", path = "../proto" } -toml = { version = "0.5" } url = { version = "2.2" } zeroize = { version = "1.1", features = ["zeroize_derive"] } flex-error = { version = "0.4.1", default-features = false } diff --git a/tendermint/src/error.rs b/tendermint/src/error.rs index 9dacc8669..9d66d1712 100644 --- a/tendermint/src/error.rs +++ b/tendermint/src/error.rs @@ -5,7 +5,6 @@ use crate::vote; use alloc::string::String; use core::num::TryFromIntError; use flex_error::{define_error, DisplayOnly}; -use std::io::Error as IoError; use time::OutOfRangeError; define_error! { @@ -18,15 +17,6 @@ define_error! { { detail: String } |e| { format_args!("invalid key: {}", e) }, - Io - [ DisplayOnly ] - |_| { format_args!("I/O error") }, - - FileIo - { path: String } - [ DisplayOnly ] - |e| { format_args!("failed to open file: {}", e.path) }, - Length |_| { format_args!("length error") }, @@ -186,14 +176,6 @@ define_error! { [ DisplayOnly ] |_| { format_args!("subtle encoding error") }, - SerdeJson - [ DisplayOnly ] - |_| { format_args!("serde json error") }, - - Toml - [ DisplayOnly ] - |_| { format_args!("toml de error") }, - Signature [ DisplayOnly ] |_| { format_args!("signature error") }, From 4b6888b06407bcaa115441d04002ca33b1388bfe Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 20 Sep 2021 13:55:34 +0200 Subject: [PATCH 03/16] Move tendermint::net to tendermint_config::net --- abci/src/lib.rs | 2 +- config/Cargo.toml | 1 + config/src/config.rs | 3 ++- config/src/error.rs | 4 ++++ config/src/lib.rs | 2 ++ {tendermint => config}/src/net.rs | 30 ++++++++++++++++++++++-------- config/tests/config.rs | 2 +- config/tests/mod.rs | 2 +- rpc/Cargo.toml | 1 + rpc/src/client/transport/http.rs | 2 +- rpc/tests/kvstore_fixtures.rs | 7 ++++--- tendermint/Cargo.toml | 1 - tendermint/src/error.rs | 4 ---- tendermint/src/lib.rs | 1 - tendermint/src/node/info.rs | 14 ++++---------- 15 files changed, 44 insertions(+), 32 deletions(-) rename {tendermint => config}/src/net.rs (89%) diff --git a/abci/src/lib.rs b/abci/src/lib.rs index 2d6d602bb..0ec100180 100644 --- a/abci/src/lib.rs +++ b/abci/src/lib.rs @@ -9,7 +9,7 @@ //! have them interact. In practice, the client interaction will be performed //! by a full Tendermint node. //! -//! ```rust +//! ```ignore //! use tendermint_abci::{KeyValueStoreApp, ServerBuilder, ClientBuilder}; //! use tendermint_proto::abci::{RequestEcho, RequestDeliverTx, RequestQuery}; //! diff --git a/config/Cargo.toml b/config/Cargo.toml index a561b0ddb..33ab07bb8 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -38,6 +38,7 @@ flex-error = { version = "0.4.1", default-features = false } serde = { version = "1", features = ["derive"] } serde_json = "1" toml = { version = "0.5" } +url = { version = "2.2" } [dev-dependencies] pretty_assertions = "0.7.2" diff --git a/config/src/config.rs b/config/src/config.rs index a27e29391..d7459b04c 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -6,6 +6,7 @@ //! - `node_key.rs`: `config::node_key::NodeKey` //! - `priv_validator_key.rs`: `config::priv_validator_key::PrivValidatorKey` +use crate::net; use crate::node_key::NodeKey; use crate::Error; @@ -16,7 +17,7 @@ use std::{ path::{Path, PathBuf}, str::FromStr, }; -use tendermint::{genesis::Genesis, net, node, Moniker, Timeout}; +use tendermint::{genesis::Genesis, node, Moniker, Timeout}; /// Tendermint `config.toml` file #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] diff --git a/config/src/error.rs b/config/src/error.rs index 1cafdcfd3..87321578b 100644 --- a/config/src/error.rs +++ b/config/src/error.rs @@ -26,6 +26,10 @@ define_error! { [ DisplayOnly ] |_| { format_args!("toml de error") }, + ParseUrl + [ DisplayOnly ] + |_| { format_args!("error parsing url error") }, + Tendermint [ TendermintError ] |_| { format_args!("tendermint error") }, diff --git a/config/src/lib.rs b/config/src/lib.rs index 856195ddd..9cb3cbafc 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -1,3 +1,5 @@ +pub mod net; + mod config; mod error; mod node_key; diff --git a/tendermint/src/net.rs b/config/src/net.rs similarity index 89% rename from tendermint/src/net.rs rename to config/src/net.rs index 6e9c4ceff..fd08d4875 100644 --- a/tendermint/src/net.rs +++ b/config/src/net.rs @@ -1,13 +1,13 @@ //! Remote addresses (`tcp://` or `unix://`) -use crate::{error::Error, node}; +use crate::error::Error; use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; use std::{ fmt::{self, Display}, - path::PathBuf, str::{self, FromStr}, }; +use tendermint::node::{self, info::ListenAddress}; use url::Url; /// URI prefix for TCP connections @@ -40,10 +40,23 @@ pub enum Address { /// UNIX domain sockets Unix { /// Path to a UNIX domain socket path - path: PathBuf, + path: String, }, } +impl Address { + /// Convert `ListenAddress` to a `net::Address` + pub fn from_listen_address(address: &ListenAddress) -> Option { + let raw_address = address.as_str(); + // TODO(tarcieri): validate these and handle them better at parse time + if raw_address.starts_with("tcp://") { + raw_address.parse().ok() + } else { + format!("tcp://{}", raw_address).parse().ok() + } + } +} + impl<'de> Deserialize<'de> for Address { fn deserialize>(deserializer: D) -> Result { Self::from_str(&String::deserialize(deserializer)?) @@ -64,7 +77,7 @@ impl Display for Address { host, port, } => write!(f, "{}{}@{}:{}", TCP_PREFIX, peer_id, host, port), - Address::Unix { path } => write!(f, "{}{}", UNIX_PREFIX, path.display()), + Address::Unix { path } => write!(f, "{}{}", UNIX_PREFIX, path), } } } @@ -83,7 +96,8 @@ impl FromStr for Address { match url.scheme() { "tcp" => Ok(Self::Tcp { peer_id: if !url.username().is_empty() { - Some(url.username().parse()?) + let username = url.username().parse().map_err(Error::tendermint)?; + Some(username) } else { None }, @@ -98,7 +112,7 @@ impl FromStr for Address { })?, }), "unix" => Ok(Self::Unix { - path: PathBuf::from(url.path()), + path: url.path().to_string(), }), _ => Err(Error::parse(format!("invalid address scheme: {:?}", addr))), } @@ -114,7 +128,7 @@ impl Serialize for Address { #[cfg(test)] mod tests { use super::*; - use crate::node; + use tendermint::node; const EXAMPLE_TCP_ADDR: &str = "tcp://abd636b766dcefb5322d8ca40011ec2cb35efbc2@35.192.61.41:26656"; @@ -175,7 +189,7 @@ mod tests { let addr = EXAMPLE_UNIX_ADDR.parse::
().unwrap(); match addr { Address::Unix { path } => { - assert_eq!(path.to_str().unwrap(), "/tmp/node.sock"); + assert_eq!(path, "/tmp/node.sock"); } other => panic!("unexpected address type: {:?}", other), } diff --git a/config/tests/config.rs b/config/tests/config.rs index 13bcef4da..8332cfc8b 100644 --- a/config/tests/config.rs +++ b/config/tests/config.rs @@ -6,7 +6,7 @@ mod files { #[cfg(test)] use pretty_assertions::assert_eq; use std::{fs, path::PathBuf, time::Duration}; - use tendermint::{net, node}; + use tendermint::node; use tendermint_config::*; /// Read a fixture file from the `support/config` directory diff --git a/config/tests/mod.rs b/config/tests/mod.rs index 13bcef4da..8332cfc8b 100644 --- a/config/tests/mod.rs +++ b/config/tests/mod.rs @@ -6,7 +6,7 @@ mod files { #[cfg(test)] use pretty_assertions::assert_eq; use std::{fs, path::PathBuf, time::Duration}; - use tendermint::{net, node}; + use tendermint::node; use tendermint_config::*; /// Read a fixture file from the `support/config` directory diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 4d69ddb86..b20e14b8c 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -74,6 +74,7 @@ serde = { version = "1", features = [ "derive" ] } serde_bytes = "0.11" serde_json = "1" tendermint = { version = "0.21.0", path = "../tendermint" } +tendermint-config = { version = "0.21.0", path = "../config" } tendermint-proto = { version = "0.21.0", path = "../proto" } thiserror = "1" uuid = { version = "0.8", default-features = false } diff --git a/rpc/src/client/transport/http.rs b/rpc/src/client/transport/http.rs index 40abb925c..69a96afcb 100644 --- a/rpc/src/client/transport/http.rs +++ b/rpc/src/client/transport/http.rs @@ -5,7 +5,7 @@ use crate::{Error, Scheme, SimpleRequest, Url}; use async_trait::async_trait; use std::convert::{TryFrom, TryInto}; use std::str::FromStr; -use tendermint::net; +use tendermint_config::net; /// A JSON-RPC/HTTP Tendermint RPC client (implements [`crate::Client`]). /// diff --git a/rpc/tests/kvstore_fixtures.rs b/rpc/tests/kvstore_fixtures.rs index 5948000c3..d16016cc6 100644 --- a/rpc/tests/kvstore_fixtures.rs +++ b/rpc/tests/kvstore_fixtures.rs @@ -6,6 +6,7 @@ use subtle_encoding::{base64, hex}; use tendermint::abci::transaction::Hash; use tendermint::evidence::Duration; use tendermint::public_key; +use tendermint_config::net::Address; use tendermint_rpc::{ endpoint, error::{Error, ErrorDetail}, @@ -740,14 +741,14 @@ fn incoming_fixtures() { "status" => { let result = endpoint::status::Response::from_string(content).unwrap(); assert_eq!( - result.node_info.listen_addr.to_net_address().unwrap(), - tendermint::net::Address::from_str("tcp://0.0.0.0:26656").unwrap() + 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, - tendermint::net::Address::from_str("tcp://0.0.0.0:26657").unwrap() + format!("{}", Address::from_str("tcp://0.0.0.0:26657").unwrap()) ); assert_eq!( result.node_info.other.tx_index, diff --git a/tendermint/Cargo.toml b/tendermint/Cargo.toml index 3424eb8c4..868248cf5 100644 --- a/tendermint/Cargo.toml +++ b/tendermint/Cargo.toml @@ -52,7 +52,6 @@ signature = "1.2" subtle = "2" subtle-encoding = { version = "0.5", features = ["bech32-preview"] } tendermint-proto = { version = "0.21.0", path = "../proto" } -url = { version = "2.2" } zeroize = { version = "1.1", features = ["zeroize_derive"] } flex-error = { version = "0.4.1", default-features = false } time = "0.1.40" diff --git a/tendermint/src/error.rs b/tendermint/src/error.rs index 9d66d1712..6af3c217a 100644 --- a/tendermint/src/error.rs +++ b/tendermint/src/error.rs @@ -29,10 +29,6 @@ define_error! { [ DisplayOnly] | e | { format_args!("error parsing int data: {}", e.data) }, - ParseUrl - [ DisplayOnly ] - |_| { format_args!("error parsing url error") }, - Protocol { detail: String } |e| { format_args!("protocol error: {}", e.detail) }, diff --git a/tendermint/src/lib.rs b/tendermint/src/lib.rs index f74b9df96..608f4128a 100644 --- a/tendermint/src/lib.rs +++ b/tendermint/src/lib.rs @@ -35,7 +35,6 @@ pub mod genesis; pub mod hash; pub mod merkle; mod moniker; -pub mod net; pub mod node; pub mod private_key; pub mod proposal; diff --git a/tendermint/src/node/info.rs b/tendermint/src/node/info.rs index 427813629..3d2c7b8ab 100644 --- a/tendermint/src/node/info.rs +++ b/tendermint/src/node/info.rs @@ -1,6 +1,6 @@ //! Node information (used in RPC responses) -use crate::{chain, channel::Channels, net, node, serializers, Moniker, Version}; +use crate::{chain, channel::Channels, node, serializers, Moniker, Version}; use serde::{Deserialize, Serialize}; use std::fmt::{self, Display}; @@ -58,14 +58,8 @@ impl ListenAddress { ListenAddress(s) } - /// Convert `ListenAddress` to a `net::Address` - pub fn to_net_address(&self) -> Option { - // TODO(tarcieri): validate these and handle them better at parse time - if self.0.starts_with("tcp://") { - self.0.parse().ok() - } else { - format!("tcp://{}", self.0).parse().ok() - } + pub fn as_str(&self) -> &str { + &self.0 } } @@ -82,7 +76,7 @@ pub struct OtherInfo { pub tx_index: TxIndexStatus, /// RPC address - pub rpc_address: net::Address, + pub rpc_address: String, } /// Transaction index status From 4e49034c569a7b144ef5fbf0e9435e8af3f86c29 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 20 Sep 2021 16:21:52 +0200 Subject: [PATCH 04/16] Fix tendermint-rpc error --- rpc/src/client/transport/websocket.rs | 4 ++-- tools/abci-test/src/main.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rpc/src/client/transport/websocket.rs b/rpc/src/client/transport/websocket.rs index 01ef6d715..8d5068e7d 100644 --- a/rpc/src/client/transport/websocket.rs +++ b/rpc/src/client/transport/websocket.rs @@ -24,7 +24,7 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::ops::Add; use std::str::FromStr; -use tendermint::net; +use tendermint_config::net; use tokio::time::{Duration, Instant}; use tracing::{debug, error}; @@ -806,7 +806,7 @@ mod test { use std::collections::HashMap; use std::path::PathBuf; use std::str::FromStr; - use tendermint::net; + use tendermint_config::net; use tokio::fs; use tokio::net::{TcpListener, TcpStream}; use tokio::task::JoinHandle; diff --git a/tools/abci-test/src/main.rs b/tools/abci-test/src/main.rs index 6dfd072e1..e69cf48a3 100644 --- a/tools/abci-test/src/main.rs +++ b/tools/abci-test/src/main.rs @@ -3,7 +3,7 @@ use futures::StreamExt; use structopt::StructOpt; use tendermint::abci::Transaction; -use tendermint::net::Address; +use tendermint_config::net::Address; use tendermint_rpc::event::EventData; use tendermint_rpc::query::EventType; use tendermint_rpc::{Client, SubscriptionClient, WebSocketClient}; From 8fc00bb83aeaff7981b19f6e47021f07d90c042b Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 21 Sep 2021 13:49:10 +0200 Subject: [PATCH 05/16] Update Cargo.toml for tendermint-config --- config/Cargo.toml | 8 +++----- config/src/lib.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/config/Cargo.toml b/config/Cargo.toml index 33ab07bb8..64a79d03f 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -11,11 +11,9 @@ keywords = ["blockchain", "bft", "consensus", "cosmos", "tendermint"] edition = "2018" description = """ - Tendermint is a high-performance blockchain consensus engine that powers - Byzantine fault tolerant applications written in any programming language. - This crate provides core types for representing information about Tendermint - blockchain networks, including chain information types, secret connections, - and remote procedure calls (JSON-RPC). + tendermint-config provides functions for loading and validating Tendermint + configuration files. It is moved out of the tendermint crate for no_std support + in the tendermint crate. """ authors = [ diff --git a/config/src/lib.rs b/config/src/lib.rs index 9cb3cbafc..cfde7d4a2 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -1,3 +1,20 @@ +//! Tendermint Configuration Utilities +//! +//! This crate defines the [`TendermintConfig`] type, which is used by +//! crates such as `tendermint-rpc` to perform operations based on +//! a common configuration type. + +#![cfg_attr(docsrs, feature(doc_cfg))] +#![allow(dead_code)] +#![deny( + warnings, + trivial_casts, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications +)] +#![forbid(unsafe_code)] + pub mod net; mod config; From ba205e242818ee371d74bcda68d7b8f56b104954 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 22 Sep 2021 15:42:54 +0200 Subject: [PATCH 06/16] Remove #![allow(dead_code)] --- config/src/lib.rs | 1 - tendermint/src/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/config/src/lib.rs b/config/src/lib.rs index cfde7d4a2..06ef0eb50 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -5,7 +5,6 @@ //! a common configuration type. #![cfg_attr(docsrs, feature(doc_cfg))] -#![allow(dead_code)] #![deny( warnings, trivial_casts, diff --git a/tendermint/src/lib.rs b/tendermint/src/lib.rs index 608f4128a..288ff232f 100644 --- a/tendermint/src/lib.rs +++ b/tendermint/src/lib.rs @@ -5,7 +5,6 @@ //! and remote procedure calls (JSON-RPC). #![cfg_attr(docsrs, feature(doc_cfg))] -#![allow(dead_code)] #![deny( warnings, trivial_casts, From 218ab1736d10920d218e5ce0240727986a113e50 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 27 Sep 2021 10:34:30 +0200 Subject: [PATCH 07/16] Apply suggestions from code review Co-authored-by: Thane Thomson --- config/Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/config/Cargo.toml b/config/Cargo.toml index 64a79d03f..f97e458cf 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tendermint-config" -version = "0.21.0" # Also update `html_root_url` in lib.rs and +version = "0.22.0" # Also update `html_root_url` in lib.rs and # depending crates (rpc, light-node, ..) when bumping this license = "Apache-2.0" homepage = "https://www.tendermint.com/" @@ -18,9 +18,6 @@ description = """ authors = [ "Informal Systems ", - "Ismail Khoffi ", - "ValarDragon ", - "Tony Arcieri ", ] [package.metadata.docs.rs] From 4c7a2939f1dd317543211df4d9ad22e877bb4806 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 27 Sep 2021 10:42:15 +0200 Subject: [PATCH 08/16] Move tendermint_config::files::test to tendermint_config::test --- config/tests/mod.rs | 466 ++++++++++++++++++++++---------------------- 1 file changed, 232 insertions(+), 234 deletions(-) diff --git a/config/tests/mod.rs b/config/tests/mod.rs index 8332cfc8b..0db1b5f54 100644 --- a/config/tests/mod.rs +++ b/config/tests/mod.rs @@ -2,238 +2,236 @@ //! //! Test config files are located in the `tests/support/config` subdirectory. -mod files { - #[cfg(test)] - use pretty_assertions::assert_eq; - use std::{fs, path::PathBuf, time::Duration}; - use tendermint::node; - use tendermint_config::*; - - /// Read a fixture file from the `support/config` directory - fn read_fixture(name: &str) -> String { - fs::read_to_string(PathBuf::from("./tests/support/config/").join(name)).unwrap() - } - - /// Parse an example `config.toml` file to a `TendermintConfig` struct - #[allow(clippy::cognitive_complexity)] - #[test] - fn config_toml_parser() { - let config_toml = read_fixture("config.toml"); - let config = TendermintConfig::parse_toml(&config_toml).unwrap(); - - // main base config options - - assert_eq!( - config.proxy_app, - "tcp://127.0.0.1:26658".parse::().unwrap() - ); - assert_eq!(config.moniker.as_ref(), "technodrome"); - assert!(config.fast_sync); - assert_eq!(config.db_backend, DbBackend::GoLevelDb); - assert_eq!(config.db_dir, PathBuf::from("data")); - assert_eq!(config.log_level.global, Some("info".to_string())); - assert_eq!(config.log_level.get("main"), Some("info")); - assert_eq!(config.log_level.get("state"), Some("info")); - assert_eq!(config.log_level.get("*"), Some("info")); - assert_eq!(config.log_format, LogFormat::Plain); - assert_eq!(config.genesis_file, PathBuf::from("config/genesis.json")); - assert_eq!( - config.priv_validator_key_file, - Some(PathBuf::from("config/priv_validator_key.json")) - ); - assert_eq!( - config.priv_validator_state_file, - PathBuf::from("data/priv_validator_state.json") - ); - assert_eq!(config.priv_validator_laddr, None); - assert_eq!(config.node_key_file, PathBuf::from("config/node_key.json")); - assert_eq!(config.abci, AbciMode::Socket); - assert!(!config.filter_peers); - - // rpc server configuration options - - let rpc = &config.rpc; - assert_eq!( - rpc.laddr, - "tcp://0.0.0.0:26657".parse::().unwrap() - ); - assert!(rpc.cors_allowed_origins.is_empty()); - assert_eq!(rpc.cors_allowed_methods.len(), 3); - assert_eq!(rpc.cors_allowed_methods[0].as_ref(), "HEAD"); - assert_eq!(rpc.cors_allowed_methods[1].as_ref(), "GET"); - assert_eq!(rpc.cors_allowed_methods[2].as_ref(), "POST"); - assert_eq!(rpc.cors_allowed_headers.len(), 5); - assert_eq!(rpc.cors_allowed_headers[0].as_ref(), "Origin"); - assert_eq!(rpc.cors_allowed_headers[1].as_ref(), "Accept"); - assert_eq!(rpc.cors_allowed_headers[2].as_ref(), "Content-Type"); - assert_eq!(rpc.cors_allowed_headers[3].as_ref(), "X-Requested-With"); - assert_eq!(rpc.cors_allowed_headers[4].as_ref(), "X-Server-Time"); - assert_eq!(rpc.grpc_laddr, None); - assert_eq!(rpc.grpc_max_open_connections, 900); - assert!(!rpc.unsafe_commands); - assert_eq!(rpc.max_open_connections, 900); - assert_eq!(rpc.max_subscription_clients, 100); - assert_eq!(rpc.max_subscriptions_per_client, 5); - assert_eq!(*rpc.timeout_broadcast_tx_commit, Duration::from_secs(10)); - assert_eq!(rpc.tls_cert_file, None); - assert_eq!(rpc.tls_key_file, None); - - // peer to peer configuration options - - let p2p = &config.p2p; - assert_eq!( - p2p.laddr, - "tcp://0.0.0.0:26656".parse::().unwrap() - ); - assert_eq!(p2p.external_address, None); - assert_eq!(p2p.seeds.len(), 2); - assert_eq!( - p2p.seeds[0], - "tcp://c2e1bde78877975b31e6f06e77da200a38048e2b@seed-1.example.com:26656" - .parse::() - .unwrap() - ); - assert_eq!( - p2p.seeds[1], - "tcp://0eafed3e9e76f626a299e1b8a79454fffe9ca83c@seed-2.example.com:26656" - .parse::() - .unwrap() - ); - assert_eq!(p2p.persistent_peers.len(), 2); - assert_eq!( - p2p.persistent_peers[0], - "tcp://70d834561f91613153e4a873f01a2cbbf1b9678d@1.2.3.4:26656" - .parse::() - .unwrap() - ); - assert_eq!( - p2p.persistent_peers[1], - "tcp://f68ed33a0baa0c734a939a9e60659566adc725cd@peer-2.example.com:26656" - .parse::() - .unwrap() - ); - assert!(!p2p.upnp); - assert_eq!(p2p.addr_book_file, PathBuf::from("config/addrbook.json")); - assert!(p2p.addr_book_strict); - assert_eq!(p2p.max_num_inbound_peers, 40); - assert_eq!(p2p.max_num_outbound_peers, 10); - assert_eq!(*p2p.flush_throttle_timeout, Duration::from_millis(100)); - assert_eq!(p2p.max_packet_msg_payload_size, 1024); - assert_eq!(p2p.send_rate.bytes_per_sec(), 5_120_000); - assert_eq!(p2p.recv_rate.bytes_per_sec(), 5_120_000); - assert!(p2p.pex); - assert!(!p2p.seed_mode); - assert_eq!(p2p.private_peer_ids.len(), 3); - assert_eq!( - p2p.private_peer_ids[0], - "8112E5C5AB6A48ADCC0E875D58A4264A2639F6A8" - .parse::() - .unwrap() - ); - assert_eq!( - p2p.private_peer_ids[1], - "3D1B9086E48C7BDF7F0D766351EED812A75DE500" - .parse::() - .unwrap() - ); - assert_eq!( - p2p.private_peer_ids[2], - "A7306AEE50627E68177A002BADD3BA4A45301AD4" - .parse::() - .unwrap() - ); - assert!(!p2p.allow_duplicate_ip); - assert_eq!(*p2p.handshake_timeout, Duration::from_secs(20)); - assert_eq!(*p2p.dial_timeout, Duration::from_secs(3)); - - // mempool configuration options - - let mempool = &config.mempool; - assert!(mempool.recheck); - assert!(mempool.broadcast); - assert_eq!(mempool.wal_dir, None); - assert_eq!(mempool.size, 5000); - assert_eq!(mempool.max_txs_bytes, 1_073_741_824); - assert_eq!(mempool.cache_size, 10000); - - // consensus configuration options - - let consensus = &config.consensus; - assert_eq!(consensus.wal_file, PathBuf::from("data/cs.wal/wal")); - assert_eq!(*consensus.timeout_propose, Duration::from_secs(3)); - assert_eq!(*consensus.timeout_propose_delta, Duration::from_millis(500)); - assert_eq!(*consensus.timeout_prevote, Duration::from_secs(1)); - assert_eq!(*consensus.timeout_prevote_delta, Duration::from_millis(500)); - assert_eq!(*consensus.timeout_precommit, Duration::from_secs(1)); - assert_eq!( - *consensus.timeout_precommit_delta, - Duration::from_millis(500) - ); - assert_eq!(*consensus.timeout_commit, Duration::from_secs(5)); - assert!(!consensus.skip_timeout_commit); - assert_eq!( - *consensus.create_empty_blocks_interval, - Duration::from_secs(0) - ); - assert_eq!( - *consensus.peer_gossip_sleep_duration, - Duration::from_millis(100) - ); - assert_eq!( - *consensus.peer_query_maj23_sleep_duration, - Duration::from_secs(2) - ); - - // transactions indexer configuration options - - let tx_index = &config.tx_index; - assert_eq!(tx_index.indexer, TxIndexer::Kv); - - // instrumentation configuration options - - let instrumentation = &config.instrumentation; - assert!(!instrumentation.prometheus); - assert_eq!(instrumentation.prometheus_listen_addr, ":26660"); - assert_eq!(instrumentation.max_open_connections, 3); - assert_eq!(instrumentation.namespace, "tendermint"); - } - - /// Parse an example `node_key.json` file to a `NodeKey` struct - #[test] - fn node_key_parser() { - let raw_node_key = read_fixture("node_key.json"); - let node_key = NodeKey::parse_json(&raw_node_key).unwrap(); - assert_eq!( - node_key.node_id().to_string(), - "1A7B6BCF3D6FB055AB3AEBCA415847531B626699" - ); - } - - /// Parse an example `priv_validator_key.json` to a `PrivValidatorKey` struct - #[test] - fn priv_validator_json_parser() { - let raw_priv_validator_key = read_fixture("priv_validator_key.json"); - let priv_validator_key = PrivValidatorKey::parse_json(&raw_priv_validator_key).unwrap(); - assert_eq!( - priv_validator_key.consensus_pubkey().to_hex(), - "F26BF4B2A2E84CEB7A53C3F1AE77408779B20064782FBADBDF0E365959EE4534" - ); - } - - /// Parse an example `config.toml` file to a `TendermintConfig` struct, then - /// serialize it and parse again. - #[test] - fn parsing_roundtrip() { - let config_toml = read_fixture("config.toml"); - let config = TendermintConfig::parse_toml(&config_toml).unwrap(); - - let written_config_toml = toml::to_string(&config).unwrap(); - let written_config = TendermintConfig::parse_toml(&written_config_toml).unwrap(); - - assert_eq!( - config, written_config, - "written config {}", - written_config_toml - ); - } +#[cfg(test)] +use pretty_assertions::assert_eq; +use std::{fs, path::PathBuf, time::Duration}; +use tendermint::node; +use tendermint_config::*; + +/// Read a fixture file from the `support/config` directory +fn read_fixture(name: &str) -> String { + fs::read_to_string(PathBuf::from("./tests/support/config/").join(name)).unwrap() +} + +/// Parse an example `config.toml` file to a `TendermintConfig` struct +#[allow(clippy::cognitive_complexity)] +#[test] +fn config_toml_parser() { + let config_toml = read_fixture("config.toml"); + let config = TendermintConfig::parse_toml(&config_toml).unwrap(); + + // main base config options + + assert_eq!( + config.proxy_app, + "tcp://127.0.0.1:26658".parse::().unwrap() + ); + assert_eq!(config.moniker.as_ref(), "technodrome"); + assert!(config.fast_sync); + assert_eq!(config.db_backend, DbBackend::GoLevelDb); + assert_eq!(config.db_dir, PathBuf::from("data")); + assert_eq!(config.log_level.global, Some("info".to_string())); + assert_eq!(config.log_level.get("main"), Some("info")); + assert_eq!(config.log_level.get("state"), Some("info")); + assert_eq!(config.log_level.get("*"), Some("info")); + assert_eq!(config.log_format, LogFormat::Plain); + assert_eq!(config.genesis_file, PathBuf::from("config/genesis.json")); + assert_eq!( + config.priv_validator_key_file, + Some(PathBuf::from("config/priv_validator_key.json")) + ); + assert_eq!( + config.priv_validator_state_file, + PathBuf::from("data/priv_validator_state.json") + ); + assert_eq!(config.priv_validator_laddr, None); + assert_eq!(config.node_key_file, PathBuf::from("config/node_key.json")); + assert_eq!(config.abci, AbciMode::Socket); + assert!(!config.filter_peers); + + // rpc server configuration options + + let rpc = &config.rpc; + assert_eq!( + rpc.laddr, + "tcp://0.0.0.0:26657".parse::().unwrap() + ); + assert!(rpc.cors_allowed_origins.is_empty()); + assert_eq!(rpc.cors_allowed_methods.len(), 3); + assert_eq!(rpc.cors_allowed_methods[0].as_ref(), "HEAD"); + assert_eq!(rpc.cors_allowed_methods[1].as_ref(), "GET"); + assert_eq!(rpc.cors_allowed_methods[2].as_ref(), "POST"); + assert_eq!(rpc.cors_allowed_headers.len(), 5); + assert_eq!(rpc.cors_allowed_headers[0].as_ref(), "Origin"); + assert_eq!(rpc.cors_allowed_headers[1].as_ref(), "Accept"); + assert_eq!(rpc.cors_allowed_headers[2].as_ref(), "Content-Type"); + assert_eq!(rpc.cors_allowed_headers[3].as_ref(), "X-Requested-With"); + assert_eq!(rpc.cors_allowed_headers[4].as_ref(), "X-Server-Time"); + assert_eq!(rpc.grpc_laddr, None); + assert_eq!(rpc.grpc_max_open_connections, 900); + assert!(!rpc.unsafe_commands); + assert_eq!(rpc.max_open_connections, 900); + assert_eq!(rpc.max_subscription_clients, 100); + assert_eq!(rpc.max_subscriptions_per_client, 5); + assert_eq!(*rpc.timeout_broadcast_tx_commit, Duration::from_secs(10)); + assert_eq!(rpc.tls_cert_file, None); + assert_eq!(rpc.tls_key_file, None); + + // peer to peer configuration options + + let p2p = &config.p2p; + assert_eq!( + p2p.laddr, + "tcp://0.0.0.0:26656".parse::().unwrap() + ); + assert_eq!(p2p.external_address, None); + assert_eq!(p2p.seeds.len(), 2); + assert_eq!( + p2p.seeds[0], + "tcp://c2e1bde78877975b31e6f06e77da200a38048e2b@seed-1.example.com:26656" + .parse::() + .unwrap() + ); + assert_eq!( + p2p.seeds[1], + "tcp://0eafed3e9e76f626a299e1b8a79454fffe9ca83c@seed-2.example.com:26656" + .parse::() + .unwrap() + ); + assert_eq!(p2p.persistent_peers.len(), 2); + assert_eq!( + p2p.persistent_peers[0], + "tcp://70d834561f91613153e4a873f01a2cbbf1b9678d@1.2.3.4:26656" + .parse::() + .unwrap() + ); + assert_eq!( + p2p.persistent_peers[1], + "tcp://f68ed33a0baa0c734a939a9e60659566adc725cd@peer-2.example.com:26656" + .parse::() + .unwrap() + ); + assert!(!p2p.upnp); + assert_eq!(p2p.addr_book_file, PathBuf::from("config/addrbook.json")); + assert!(p2p.addr_book_strict); + assert_eq!(p2p.max_num_inbound_peers, 40); + assert_eq!(p2p.max_num_outbound_peers, 10); + assert_eq!(*p2p.flush_throttle_timeout, Duration::from_millis(100)); + assert_eq!(p2p.max_packet_msg_payload_size, 1024); + assert_eq!(p2p.send_rate.bytes_per_sec(), 5_120_000); + assert_eq!(p2p.recv_rate.bytes_per_sec(), 5_120_000); + assert!(p2p.pex); + assert!(!p2p.seed_mode); + assert_eq!(p2p.private_peer_ids.len(), 3); + assert_eq!( + p2p.private_peer_ids[0], + "8112E5C5AB6A48ADCC0E875D58A4264A2639F6A8" + .parse::() + .unwrap() + ); + assert_eq!( + p2p.private_peer_ids[1], + "3D1B9086E48C7BDF7F0D766351EED812A75DE500" + .parse::() + .unwrap() + ); + assert_eq!( + p2p.private_peer_ids[2], + "A7306AEE50627E68177A002BADD3BA4A45301AD4" + .parse::() + .unwrap() + ); + assert!(!p2p.allow_duplicate_ip); + assert_eq!(*p2p.handshake_timeout, Duration::from_secs(20)); + assert_eq!(*p2p.dial_timeout, Duration::from_secs(3)); + + // mempool configuration options + + let mempool = &config.mempool; + assert!(mempool.recheck); + assert!(mempool.broadcast); + assert_eq!(mempool.wal_dir, None); + assert_eq!(mempool.size, 5000); + assert_eq!(mempool.max_txs_bytes, 1_073_741_824); + assert_eq!(mempool.cache_size, 10000); + + // consensus configuration options + + let consensus = &config.consensus; + assert_eq!(consensus.wal_file, PathBuf::from("data/cs.wal/wal")); + assert_eq!(*consensus.timeout_propose, Duration::from_secs(3)); + assert_eq!(*consensus.timeout_propose_delta, Duration::from_millis(500)); + assert_eq!(*consensus.timeout_prevote, Duration::from_secs(1)); + assert_eq!(*consensus.timeout_prevote_delta, Duration::from_millis(500)); + assert_eq!(*consensus.timeout_precommit, Duration::from_secs(1)); + assert_eq!( + *consensus.timeout_precommit_delta, + Duration::from_millis(500) + ); + assert_eq!(*consensus.timeout_commit, Duration::from_secs(5)); + assert!(!consensus.skip_timeout_commit); + assert_eq!( + *consensus.create_empty_blocks_interval, + Duration::from_secs(0) + ); + assert_eq!( + *consensus.peer_gossip_sleep_duration, + Duration::from_millis(100) + ); + assert_eq!( + *consensus.peer_query_maj23_sleep_duration, + Duration::from_secs(2) + ); + + // transactions indexer configuration options + + let tx_index = &config.tx_index; + assert_eq!(tx_index.indexer, TxIndexer::Kv); + + // instrumentation configuration options + + let instrumentation = &config.instrumentation; + assert!(!instrumentation.prometheus); + assert_eq!(instrumentation.prometheus_listen_addr, ":26660"); + assert_eq!(instrumentation.max_open_connections, 3); + assert_eq!(instrumentation.namespace, "tendermint"); +} + +/// Parse an example `node_key.json` file to a `NodeKey` struct +#[test] +fn node_key_parser() { + let raw_node_key = read_fixture("node_key.json"); + let node_key = NodeKey::parse_json(&raw_node_key).unwrap(); + assert_eq!( + node_key.node_id().to_string(), + "1A7B6BCF3D6FB055AB3AEBCA415847531B626699" + ); +} + +/// Parse an example `priv_validator_key.json` to a `PrivValidatorKey` struct +#[test] +fn priv_validator_json_parser() { + let raw_priv_validator_key = read_fixture("priv_validator_key.json"); + let priv_validator_key = PrivValidatorKey::parse_json(&raw_priv_validator_key).unwrap(); + assert_eq!( + priv_validator_key.consensus_pubkey().to_hex(), + "F26BF4B2A2E84CEB7A53C3F1AE77408779B20064782FBADBDF0E365959EE4534" + ); +} + +/// Parse an example `config.toml` file to a `TendermintConfig` struct, then +/// serialize it and parse again. +#[test] +fn parsing_roundtrip() { + let config_toml = read_fixture("config.toml"); + let config = TendermintConfig::parse_toml(&config_toml).unwrap(); + + let written_config_toml = toml::to_string(&config).unwrap(); + let written_config = TendermintConfig::parse_toml(&written_config_toml).unwrap(); + + assert_eq!( + config, written_config, + "written config {}", + written_config_toml + ); } From 29ff94fa2e19bf8d94b379ad49efc0e3e53c518e Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 27 Sep 2021 10:44:56 +0200 Subject: [PATCH 09/16] Remove config/tests/config.rs --- config/tests/config.rs | 239 ----------------------------------------- 1 file changed, 239 deletions(-) delete mode 100644 config/tests/config.rs diff --git a/config/tests/config.rs b/config/tests/config.rs deleted file mode 100644 index 8332cfc8b..000000000 --- a/config/tests/config.rs +++ /dev/null @@ -1,239 +0,0 @@ -//! Tests for parsing configuration files. -//! -//! Test config files are located in the `tests/support/config` subdirectory. - -mod files { - #[cfg(test)] - use pretty_assertions::assert_eq; - use std::{fs, path::PathBuf, time::Duration}; - use tendermint::node; - use tendermint_config::*; - - /// Read a fixture file from the `support/config` directory - fn read_fixture(name: &str) -> String { - fs::read_to_string(PathBuf::from("./tests/support/config/").join(name)).unwrap() - } - - /// Parse an example `config.toml` file to a `TendermintConfig` struct - #[allow(clippy::cognitive_complexity)] - #[test] - fn config_toml_parser() { - let config_toml = read_fixture("config.toml"); - let config = TendermintConfig::parse_toml(&config_toml).unwrap(); - - // main base config options - - assert_eq!( - config.proxy_app, - "tcp://127.0.0.1:26658".parse::().unwrap() - ); - assert_eq!(config.moniker.as_ref(), "technodrome"); - assert!(config.fast_sync); - assert_eq!(config.db_backend, DbBackend::GoLevelDb); - assert_eq!(config.db_dir, PathBuf::from("data")); - assert_eq!(config.log_level.global, Some("info".to_string())); - assert_eq!(config.log_level.get("main"), Some("info")); - assert_eq!(config.log_level.get("state"), Some("info")); - assert_eq!(config.log_level.get("*"), Some("info")); - assert_eq!(config.log_format, LogFormat::Plain); - assert_eq!(config.genesis_file, PathBuf::from("config/genesis.json")); - assert_eq!( - config.priv_validator_key_file, - Some(PathBuf::from("config/priv_validator_key.json")) - ); - assert_eq!( - config.priv_validator_state_file, - PathBuf::from("data/priv_validator_state.json") - ); - assert_eq!(config.priv_validator_laddr, None); - assert_eq!(config.node_key_file, PathBuf::from("config/node_key.json")); - assert_eq!(config.abci, AbciMode::Socket); - assert!(!config.filter_peers); - - // rpc server configuration options - - let rpc = &config.rpc; - assert_eq!( - rpc.laddr, - "tcp://0.0.0.0:26657".parse::().unwrap() - ); - assert!(rpc.cors_allowed_origins.is_empty()); - assert_eq!(rpc.cors_allowed_methods.len(), 3); - assert_eq!(rpc.cors_allowed_methods[0].as_ref(), "HEAD"); - assert_eq!(rpc.cors_allowed_methods[1].as_ref(), "GET"); - assert_eq!(rpc.cors_allowed_methods[2].as_ref(), "POST"); - assert_eq!(rpc.cors_allowed_headers.len(), 5); - assert_eq!(rpc.cors_allowed_headers[0].as_ref(), "Origin"); - assert_eq!(rpc.cors_allowed_headers[1].as_ref(), "Accept"); - assert_eq!(rpc.cors_allowed_headers[2].as_ref(), "Content-Type"); - assert_eq!(rpc.cors_allowed_headers[3].as_ref(), "X-Requested-With"); - assert_eq!(rpc.cors_allowed_headers[4].as_ref(), "X-Server-Time"); - assert_eq!(rpc.grpc_laddr, None); - assert_eq!(rpc.grpc_max_open_connections, 900); - assert!(!rpc.unsafe_commands); - assert_eq!(rpc.max_open_connections, 900); - assert_eq!(rpc.max_subscription_clients, 100); - assert_eq!(rpc.max_subscriptions_per_client, 5); - assert_eq!(*rpc.timeout_broadcast_tx_commit, Duration::from_secs(10)); - assert_eq!(rpc.tls_cert_file, None); - assert_eq!(rpc.tls_key_file, None); - - // peer to peer configuration options - - let p2p = &config.p2p; - assert_eq!( - p2p.laddr, - "tcp://0.0.0.0:26656".parse::().unwrap() - ); - assert_eq!(p2p.external_address, None); - assert_eq!(p2p.seeds.len(), 2); - assert_eq!( - p2p.seeds[0], - "tcp://c2e1bde78877975b31e6f06e77da200a38048e2b@seed-1.example.com:26656" - .parse::() - .unwrap() - ); - assert_eq!( - p2p.seeds[1], - "tcp://0eafed3e9e76f626a299e1b8a79454fffe9ca83c@seed-2.example.com:26656" - .parse::() - .unwrap() - ); - assert_eq!(p2p.persistent_peers.len(), 2); - assert_eq!( - p2p.persistent_peers[0], - "tcp://70d834561f91613153e4a873f01a2cbbf1b9678d@1.2.3.4:26656" - .parse::() - .unwrap() - ); - assert_eq!( - p2p.persistent_peers[1], - "tcp://f68ed33a0baa0c734a939a9e60659566adc725cd@peer-2.example.com:26656" - .parse::() - .unwrap() - ); - assert!(!p2p.upnp); - assert_eq!(p2p.addr_book_file, PathBuf::from("config/addrbook.json")); - assert!(p2p.addr_book_strict); - assert_eq!(p2p.max_num_inbound_peers, 40); - assert_eq!(p2p.max_num_outbound_peers, 10); - assert_eq!(*p2p.flush_throttle_timeout, Duration::from_millis(100)); - assert_eq!(p2p.max_packet_msg_payload_size, 1024); - assert_eq!(p2p.send_rate.bytes_per_sec(), 5_120_000); - assert_eq!(p2p.recv_rate.bytes_per_sec(), 5_120_000); - assert!(p2p.pex); - assert!(!p2p.seed_mode); - assert_eq!(p2p.private_peer_ids.len(), 3); - assert_eq!( - p2p.private_peer_ids[0], - "8112E5C5AB6A48ADCC0E875D58A4264A2639F6A8" - .parse::() - .unwrap() - ); - assert_eq!( - p2p.private_peer_ids[1], - "3D1B9086E48C7BDF7F0D766351EED812A75DE500" - .parse::() - .unwrap() - ); - assert_eq!( - p2p.private_peer_ids[2], - "A7306AEE50627E68177A002BADD3BA4A45301AD4" - .parse::() - .unwrap() - ); - assert!(!p2p.allow_duplicate_ip); - assert_eq!(*p2p.handshake_timeout, Duration::from_secs(20)); - assert_eq!(*p2p.dial_timeout, Duration::from_secs(3)); - - // mempool configuration options - - let mempool = &config.mempool; - assert!(mempool.recheck); - assert!(mempool.broadcast); - assert_eq!(mempool.wal_dir, None); - assert_eq!(mempool.size, 5000); - assert_eq!(mempool.max_txs_bytes, 1_073_741_824); - assert_eq!(mempool.cache_size, 10000); - - // consensus configuration options - - let consensus = &config.consensus; - assert_eq!(consensus.wal_file, PathBuf::from("data/cs.wal/wal")); - assert_eq!(*consensus.timeout_propose, Duration::from_secs(3)); - assert_eq!(*consensus.timeout_propose_delta, Duration::from_millis(500)); - assert_eq!(*consensus.timeout_prevote, Duration::from_secs(1)); - assert_eq!(*consensus.timeout_prevote_delta, Duration::from_millis(500)); - assert_eq!(*consensus.timeout_precommit, Duration::from_secs(1)); - assert_eq!( - *consensus.timeout_precommit_delta, - Duration::from_millis(500) - ); - assert_eq!(*consensus.timeout_commit, Duration::from_secs(5)); - assert!(!consensus.skip_timeout_commit); - assert_eq!( - *consensus.create_empty_blocks_interval, - Duration::from_secs(0) - ); - assert_eq!( - *consensus.peer_gossip_sleep_duration, - Duration::from_millis(100) - ); - assert_eq!( - *consensus.peer_query_maj23_sleep_duration, - Duration::from_secs(2) - ); - - // transactions indexer configuration options - - let tx_index = &config.tx_index; - assert_eq!(tx_index.indexer, TxIndexer::Kv); - - // instrumentation configuration options - - let instrumentation = &config.instrumentation; - assert!(!instrumentation.prometheus); - assert_eq!(instrumentation.prometheus_listen_addr, ":26660"); - assert_eq!(instrumentation.max_open_connections, 3); - assert_eq!(instrumentation.namespace, "tendermint"); - } - - /// Parse an example `node_key.json` file to a `NodeKey` struct - #[test] - fn node_key_parser() { - let raw_node_key = read_fixture("node_key.json"); - let node_key = NodeKey::parse_json(&raw_node_key).unwrap(); - assert_eq!( - node_key.node_id().to_string(), - "1A7B6BCF3D6FB055AB3AEBCA415847531B626699" - ); - } - - /// Parse an example `priv_validator_key.json` to a `PrivValidatorKey` struct - #[test] - fn priv_validator_json_parser() { - let raw_priv_validator_key = read_fixture("priv_validator_key.json"); - let priv_validator_key = PrivValidatorKey::parse_json(&raw_priv_validator_key).unwrap(); - assert_eq!( - priv_validator_key.consensus_pubkey().to_hex(), - "F26BF4B2A2E84CEB7A53C3F1AE77408779B20064782FBADBDF0E365959EE4534" - ); - } - - /// Parse an example `config.toml` file to a `TendermintConfig` struct, then - /// serialize it and parse again. - #[test] - fn parsing_roundtrip() { - let config_toml = read_fixture("config.toml"); - let config = TendermintConfig::parse_toml(&config_toml).unwrap(); - - let written_config_toml = toml::to_string(&config).unwrap(); - let written_config = TendermintConfig::parse_toml(&written_config_toml).unwrap(); - - assert_eq!( - config, written_config, - "written config {}", - written_config_toml - ); - } -} From ddd7d40e996a063f2e72226ea06002d0229fc650 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 28 Sep 2021 13:15:05 +0200 Subject: [PATCH 10/16] Minor fixes --- abci/src/lib.rs | 2 +- config/src/node_key.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/abci/src/lib.rs b/abci/src/lib.rs index 0ec100180..6b38657d6 100644 --- a/abci/src/lib.rs +++ b/abci/src/lib.rs @@ -9,7 +9,7 @@ //! have them interact. In practice, the client interaction will be performed //! by a full Tendermint node. //! -//! ```ignore +//! ``` //! use tendermint_abci::{KeyValueStoreApp, ServerBuilder, ClientBuilder}; //! use tendermint_proto::abci::{RequestEcho, RequestDeliverTx, RequestQuery}; //! diff --git a/config/src/node_key.rs b/config/src/node_key.rs index 61543cf4a..981119c2d 100644 --- a/config/src/node_key.rs +++ b/config/src/node_key.rs @@ -33,9 +33,10 @@ impl NodeKey { /// Get the public key for this keypair pub fn public_key(&self) -> PublicKey { + #[allow(unreachable_patterns)] match &self.priv_key { PrivateKey::Ed25519(keypair) => keypair.public.into(), - _ => todo!(), + _ => unreachable!(), } } From 540e37f1c6b9bfd787941313dced23dd0d67b081 Mon Sep 17 00:00:00 2001 From: Thane Thomson Date: Wed, 6 Oct 2021 03:32:36 -0400 Subject: [PATCH 11/16] Resolve conflict in #986 (#1004) * Fix `cargo test` and add check to CI (#990) * Relocate ABCI test to fix broken doctest Signed-off-by: Thane Thomson * Use tokio_test for mock client doctest Signed-off-by: Thane Thomson * Add CI test for default features Signed-off-by: Thane Thomson * Add `block_search` RPC endpoint (#991) * Add block_search RPC endpoint and tests * Add .changelog entry * Fix comments * tools: Fix `block_search` endpoint integration tests (#999) Closes #998 * Bump integration test tendermint to v0.34.13 * Fix kvstore integration tests * Bump tendermint version to v0.34.13 in CI Signed-off-by: Thane Thomson * ci: Build and check tools (#997) So far only the kvstore tests ran as part of the Github workfows. This would leave opportunity for changes to introduce breakage to the builds of the tools. In this change the same build and clippy stages are introduced for the tools workspace that currently run for the top-level one. Signed-off-by: xla * tools: Add `block_search` method to RPC probe (#1002) * Add missing block_search endpoint * Bump tendermint version to v0.34.13 Signed-off-by: Thane Thomson Co-authored-by: Shoaib Ahmed Co-authored-by: xla --- .cargo/config | 1 + .../unreleased/features/832-block-search.md | 3 + .github/workflows/build.yml | 12 ++++ .github/workflows/rust.yml | 15 ++++ .github/workflows/test.yml | 18 ++++- abci/src/application/kvstore.rs | 45 ++++++++++++ abci/src/lib.rs | 51 -------------- rpc/Cargo.toml | 1 + rpc/src/client.rs | 12 ++++ rpc/src/client/bin/main.rs | 21 ++++++ rpc/src/client/transport/mock.rs | 5 +- rpc/src/endpoint.rs | 1 + rpc/src/endpoint/block_search.rs | 48 +++++++++++++ rpc/src/method.rs | 5 ++ rpc/tests/kvstore_fixtures.rs | 53 ++++++++++++++ .../incoming/block_search.json | 70 +++++++++++++++++++ .../outgoing/block_search.json | 11 +++ tools/kvstore-test/Makefile.toml | 2 +- tools/kvstore-test/tests/tendermint.rs | 37 +++++++--- tools/rpc-probe/Makefile.toml | 2 +- tools/rpc-probe/src/kvstore.rs | 13 ++++ tools/rpc-probe/src/quick.rs | 1 + 22 files changed, 360 insertions(+), 67 deletions(-) create mode 100644 .changelog/unreleased/features/832-block-search.md create mode 100644 rpc/src/endpoint/block_search.rs create mode 100644 rpc/tests/kvstore_fixtures/incoming/block_search.json create mode 100644 rpc/tests/kvstore_fixtures/outgoing/block_search.json diff --git a/.cargo/config b/.cargo/config index 3a3045ebd..44cee77fd 100644 --- a/.cargo/config +++ b/.cargo/config @@ -3,4 +3,5 @@ build-all = "build --workspace --all-targets --" build-wasm-tendermint = "build -p tendermint --manifest-path tendermint/Cargo.toml --target wasm32-unknown-unknown --release --no-default-features --" build-wasm-light-client = "build -p tendermint-light-client --manifest-path light-client/Cargo.toml --target wasm32-unknown-unknown --release --no-default-features --" build-abci = "build --manifest-path abci/Cargo.toml --bin kvstore-rs --features binary,kvstore-app" +build-tools = "build --manifest-path tools/Cargo.toml --all-features --all-targets --workspace" test-all-features = "test --all-features --no-fail-fast" diff --git a/.changelog/unreleased/features/832-block-search.md b/.changelog/unreleased/features/832-block-search.md new file mode 100644 index 000000000..db05e839f --- /dev/null +++ b/.changelog/unreleased/features/832-block-search.md @@ -0,0 +1,3 @@ +- `[tendermint-rpc]` Add support for the `/block_search` RPC endpoint. See + for details +([#832](https://github.com/informalsystems/tendermint-rs/issues/832)) \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 284645a01..6864adb89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,3 +44,15 @@ jobs: - uses: actions-rs/cargo@v1 with: command: build-wasm-light-client + + tools: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: build-tools diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 35075051c..615d72b76 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -46,6 +46,21 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} args: --all-features --all-targets -- -Dwarnings -Drust-2018-idioms + clippy-tools-output: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: clippy + override: true + - uses: actions-rs/clippy-check@v1 + with: + name: clippy-tools-results + token: ${{ secrets.GITHUB_TOKEN }} + args: --manifest-path tools/kvstore-test/Cargo.toml --all-features --all-targets -- -Dwarnings -Drust-2018-idioms + docs: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index be690a54c..50a0de436 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,6 +17,18 @@ jobs: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" + default-features: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + # TODO(shonfeder): remove duplication once GitHub addresses one of these # - https://github.community/t/support-for-yaml-anchors/16128/15 # - https://github.community/t/reusing-sharing-inheriting-steps-between-jobs-declarations/16851/13 @@ -33,6 +45,7 @@ jobs: with: command: test-all-features args: -p tendermint + tendermint-rpc: runs-on: ubuntu-latest steps: @@ -45,6 +58,7 @@ jobs: with: command: test-all-features args: -p tendermint-rpc + tendermint-proto: runs-on: ubuntu-latest steps: @@ -57,6 +71,7 @@ jobs: with: command: test-all-features args: -p tendermint-proto + tendermint-light-client: runs-on: ubuntu-latest steps: @@ -69,6 +84,7 @@ jobs: with: command: test-all-features args: -p tendermint-light-client + # From https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/continuous-integration.html#github-actions tendermint-light-client-js: runs-on: ubuntu-latest @@ -109,7 +125,7 @@ jobs: runs-on: ubuntu-latest services: tendermint: - image: informaldev/tendermint:0.34.0 + image: informaldev/tendermint:0.34.13 ports: - 26656:26656 - 26657:26657 diff --git a/abci/src/application/kvstore.rs b/abci/src/application/kvstore.rs index 4c174fca2..57a687345 100644 --- a/abci/src/application/kvstore.rs +++ b/abci/src/application/kvstore.rs @@ -15,6 +15,51 @@ use tracing::{debug, info}; /// /// This structure effectively just serves as a handle to the actual key/value /// store - the [`KeyValueStoreDriver`]. +/// +/// ## Example +/// ```rust +/// use tendermint_abci::{KeyValueStoreApp, ServerBuilder, ClientBuilder}; +/// use tendermint_proto::abci::{RequestEcho, RequestDeliverTx, RequestQuery}; +/// +/// // Create our key/value store application +/// let (app, driver) = KeyValueStoreApp::new(); +/// // Create our server, binding it to TCP port 26658 on localhost and +/// // supplying it with our key/value store application +/// let server = ServerBuilder::default().bind("127.0.0.1:26658", app).unwrap(); +/// let server_addr = server.local_addr(); +/// +/// // We want the driver and the server to run in the background while we +/// // interact with them via the client in the foreground +/// std::thread::spawn(move || driver.run()); +/// std::thread::spawn(move || server.listen()); +/// +/// let mut client = ClientBuilder::default().connect(server_addr).unwrap(); +/// let res = client +/// .echo(RequestEcho { +/// message: "Hello ABCI!".to_string(), +/// }) +/// .unwrap(); +/// assert_eq!(res.message, "Hello ABCI!"); +/// +/// // Deliver a transaction and then commit the transaction +/// client +/// .deliver_tx(RequestDeliverTx { +/// tx: "test-key=test-value".as_bytes().to_owned(), +/// }) +/// .unwrap(); +/// client.commit().unwrap(); +/// +/// // We should be able to query for the data we just delivered above +/// let res = client +/// .query(RequestQuery { +/// data: "test-key".as_bytes().to_owned(), +/// path: "".to_string(), +/// height: 0, +/// prove: false, +/// }) +/// .unwrap(); +/// assert_eq!(res.value, "test-value".as_bytes().to_owned()); +/// ``` #[derive(Debug, Clone)] pub struct KeyValueStoreApp { cmd_tx: Sender, diff --git a/abci/src/lib.rs b/abci/src/lib.rs index 6b38657d6..8ec63a960 100644 --- a/abci/src/lib.rs +++ b/abci/src/lib.rs @@ -1,57 +1,6 @@ //! ABCI framework for building [Tendermint] applications in Rust. //! //! [Tendermint]: https://tendermint.com -//! -//! ## Example -//! -//! The following example is adapted from our integration test suite to -//! demonstrate how to instantiate an ABCI application, server and client and -//! have them interact. In practice, the client interaction will be performed -//! by a full Tendermint node. -//! -//! ``` -//! use tendermint_abci::{KeyValueStoreApp, ServerBuilder, ClientBuilder}; -//! use tendermint_proto::abci::{RequestEcho, RequestDeliverTx, RequestQuery}; -//! -//! // Create our key/value store application -//! let (app, driver) = KeyValueStoreApp::new(); -//! // Create our server, binding it to TCP port 26658 on localhost and -//! // supplying it with our key/value store application -//! let server = ServerBuilder::default().bind("127.0.0.1:26658", app).unwrap(); -//! let server_addr = server.local_addr(); -//! -//! // We want the driver and the server to run in the background while we -//! // interact with them via the client in the foreground -//! std::thread::spawn(move || driver.run()); -//! std::thread::spawn(move || server.listen()); -//! -//! let mut client = ClientBuilder::default().connect(server_addr).unwrap(); -//! let res = client -//! .echo(RequestEcho { -//! message: "Hello ABCI!".to_string(), -//! }) -//! .unwrap(); -//! assert_eq!(res.message, "Hello ABCI!"); -//! -//! // Deliver a transaction and then commit the transaction -//! client -//! .deliver_tx(RequestDeliverTx { -//! tx: "test-key=test-value".as_bytes().to_owned(), -//! }) -//! .unwrap(); -//! client.commit().unwrap(); -//! -//! // We should be able to query for the data we just delivered above -//! let res = client -//! .query(RequestQuery { -//! data: "test-key".as_bytes().to_owned(), -//! path: "".to_string(), -//! height: 0, -//! prove: false, -//! }) -//! .unwrap(); -//! assert_eq!(res.value, "test-value".as_bytes().to_owned()); -//! ``` mod application; #[cfg(feature = "client")] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 77d4b0893..611d10b5e 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -98,3 +98,4 @@ tracing-subscriber = { version = "0.2", optional = true } [dev-dependencies] lazy_static = "1.4.0" +tokio-test = "0.4" diff --git a/rpc/src/client.rs b/rpc/src/client.rs index 7a923f40f..2dc6e153a 100644 --- a/rpc/src/client.rs +++ b/rpc/src/client.rs @@ -85,6 +85,18 @@ pub trait Client { self.perform(block_results::Request::default()).await } + /// `/block_search`: search for blocks by BeginBlock and EndBlock events. + async fn block_search( + &self, + query: Query, + page: u32, + per_page: u8, + order: Order, + ) -> Result { + self.perform(block_search::Request::new(query, page, per_page, order)) + .await + } + /// `/blockchain`: get block headers for `min` <= `height` <= `max`. /// /// Block headers are returned in descending order (highest first). diff --git a/rpc/src/client/bin/main.rs b/rpc/src/client/bin/main.rs index 18572b553..b4e48c572 100644 --- a/rpc/src/client/bin/main.rs +++ b/rpc/src/client/bin/main.rs @@ -91,6 +91,18 @@ enum ClientRequest { /// The height of the block you want. height: u32, }, + /// Search for a block by way of a specific query. Uses the same + /// query syntax as the `subscribe` endpoint. + BlockSearch { + /// The query against which blocks should be matched. + query: Query, + #[structopt(long, default_value = "1")] + page: u32, + #[structopt(long, default_value = "10")] + per_page: u8, + #[structopt(long, default_value = "asc")] + order: Order, + }, // TODO(thane): Implement evidence broadcast /// Broadcast a transaction asynchronously (without waiting for the ABCI /// app to check it or for it to be committed). @@ -313,6 +325,15 @@ where serde_json::to_string_pretty(&client.block_results(height).await?) .map_err(Error::serde)? } + ClientRequest::BlockSearch { + query, + page, + per_page, + order, + } => { + serde_json::to_string_pretty(&client.block_search(query, page, per_page, order).await?) + .map_err(Error::serde)? + } ClientRequest::BroadcastTxAsync { tx } => serde_json::to_string_pretty( &client .broadcast_tx_async(Transaction::from(tx.into_bytes())) diff --git a/rpc/src/client/transport/mock.rs b/rpc/src/client/transport/mock.rs index 1efcabc85..c1382a8d0 100644 --- a/rpc/src/client/transport/mock.rs +++ b/rpc/src/client/transport/mock.rs @@ -31,8 +31,7 @@ use std::collections::HashMap; /// } /// }"#; /// -/// #[tokio::main] -/// async fn main() { +/// tokio_test::block_on(async { /// let matcher = MockRequestMethodMatcher::default() /// .map(Method::AbciInfo, Ok(ABCI_INFO_RESPONSE.to_string())); /// let (client, driver) = MockClient::new(matcher); @@ -44,7 +43,7 @@ use std::collections::HashMap; /// /// client.close(); /// driver_hdl.await.unwrap(); -/// } +/// }); /// ``` #[derive(Debug)] pub struct MockClient { diff --git a/rpc/src/endpoint.rs b/rpc/src/endpoint.rs index 2cee26db2..8720be10b 100644 --- a/rpc/src/endpoint.rs +++ b/rpc/src/endpoint.rs @@ -4,6 +4,7 @@ pub mod abci_info; pub mod abci_query; pub mod block; pub mod block_results; +pub mod block_search; pub mod blockchain; pub mod broadcast; pub mod commit; diff --git a/rpc/src/endpoint/block_search.rs b/rpc/src/endpoint/block_search.rs new file mode 100644 index 000000000..ef1e19c4a --- /dev/null +++ b/rpc/src/endpoint/block_search.rs @@ -0,0 +1,48 @@ +//! `/block_search` endpoint JSON-RPC wrapper + +pub use super::{block, block_results}; + +use crate::{Method, Order}; +use serde::{Deserialize, Serialize}; + +/// 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")] + pub page: u32, + #[serde(with = "tendermint_proto::serializers::from_str")] + pub per_page: u8, + pub order_by: Order, +} + +impl Request { + /// Constructor. + pub fn new(query: impl ToString, page: u32, per_page: u8, order_by: Order) -> Self { + Self { + query: query.to_string(), + page, + per_page, + order_by, + } + } +} + +impl crate::Request for Request { + type Response = Response; + + fn method(&self) -> Method { + Method::BlockSearch + } +} + +impl crate::SimpleRequest for Request {} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Response { + pub blocks: Vec, + #[serde(with = "tendermint_proto::serializers::from_str")] + pub total_count: u32, +} + +impl crate::Response for Response {} diff --git a/rpc/src/method.rs b/rpc/src/method.rs index f03c8b3b3..5a3fd47bc 100644 --- a/rpc/src/method.rs +++ b/rpc/src/method.rs @@ -24,6 +24,9 @@ pub enum Method { /// Get ABCI results for a particular block BlockResults, + /// Search for blocks by their BeginBlock and EndBlock events + BlockSearch, + /// Get blockchain info Blockchain, @@ -84,6 +87,7 @@ impl Method { Method::AbciQuery => "abci_query", Method::Block => "block", Method::BlockResults => "block_results", + Method::BlockSearch => "block_search", Method::Blockchain => "blockchain", Method::BroadcastEvidence => "broadcast_evidence", Method::BroadcastTxAsync => "broadcast_tx_async", @@ -114,6 +118,7 @@ impl FromStr for Method { "abci_query" => Method::AbciQuery, "block" => Method::Block, "block_results" => Method::BlockResults, + "block_search" => Method::BlockSearch, "blockchain" => Method::Blockchain, "broadcast_evidence" => Method::BroadcastEvidence, "broadcast_tx_async" => Method::BroadcastTxAsync, diff --git a/rpc/tests/kvstore_fixtures.rs b/rpc/tests/kvstore_fixtures.rs index d16016cc6..a69604e76 100644 --- a/rpc/tests/kvstore_fixtures.rs +++ b/rpc/tests/kvstore_fixtures.rs @@ -97,6 +97,17 @@ fn outgoing_fixtures() { .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, 10); + assert_eq!(wrapped.params().order_by, Order::Ascending); + } "blockchain_from_1_to_10" => { let wrapped = serde_json::from_str::>(&content) @@ -448,6 +459,48 @@ fn incoming_fixtures() { assert!(result.txs_results.is_none()); assert!(result.validator_updates.is_empty()); } + "block_search" => { + 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 { + assert!(block.block.data.iter().next().is_none()); + assert!(block.block.evidence.iter().next().is_none()); + assert_eq!(block.block.header.app_hash.value(), [0u8; 8]); + assert_eq!(block.block.header.chain_id.as_str(), CHAIN_ID); + assert!(!block.block.header.consensus_hash.is_empty()); + assert!(block.block.header.data_hash.is_none()); + assert!(block.block.header.evidence_hash.is_none()); + assert_eq!(block.block.header.height.value(), 10); + assert!(block.block.header.last_block_id.is_some()); + assert_eq!(block.block.header.last_commit_hash, empty_merkle_root_hash); + assert_eq!(block.block.header.last_results_hash, empty_merkle_root_hash); + assert!(!block.block.header.next_validators_hash.is_empty()); + assert_ne!( + block.block.header.proposer_address.as_bytes(), + [0u8; tendermint::account::LENGTH] + ); + assert!( + block + .block + .header + .time + .duration_since(informal_epoch) + .unwrap() + .as_secs() + > 0 + ); + assert!(!block.block.header.validators_hash.is_empty()); + assert_eq!( + block.block.header.version, + tendermint::block::header::Version { block: 10, app: 1 } + ); + assert!(block.block.last_commit.is_some()); + assert!(!block.block_id.hash.is_empty()); + assert!(!block.block_id.part_set_header.hash.is_empty()); + assert_eq!(block.block_id.part_set_header.total, 1); + } + } "blockchain_from_1_to_10" => { let result = endpoint::blockchain::Response::from_string(content).unwrap(); assert_eq!(result.block_metas.len(), 10); diff --git a/rpc/tests/kvstore_fixtures/incoming/block_search.json b/rpc/tests/kvstore_fixtures/incoming/block_search.json new file mode 100644 index 000000000..cbd74b5d7 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/incoming/block_search.json @@ -0,0 +1,70 @@ +{ + "jsonrpc": "2.0", + "id": "", + "result": { + "blocks": [ + { + "block_id": { + "hash": "4FFD15F274758E474898498A191EB8CA6FC6C466576255DA132908A12AC1674C", + "part_set_header": { + "total": 1, + "hash": "BBA710736635FA20CDB4F48732563869E90871D31FE9E7DE3D900CD4334D8775" + } + }, + "block": { + "header": { + "version": { + "block": "10", + "app": "1" + }, + "chain_id": "dockerchain", + "height": "10", + "time": "2020-03-15T16:57:08.151Z", + "last_block_id": { + "hash": "760E050B2404A4BC661635CA552FF45876BCD927C367ADF88961E389C01D32FF", + "part_set_header": { + "total": 1, + "hash": "485070D01F9543827B3F9BAF11BDCFFBFD2BDED0B63D7192FA55649B94A1D5DE" + } + }, + "last_commit_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "data_hash": "", + "validators_hash": "3C0A744897A1E0DBF1DEDE1AF339D65EDDCF10E6338504368B20C508D6D578DC", + "next_validators_hash": "3C0A744897A1E0DBF1DEDE1AF339D65EDDCF10E6338504368B20C508D6D578DC", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "app_hash": "0000000000000000", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "", + "proposer_address": "12CC3970B3AE9F19A4B1D98BE1799F2CB923E0A3" + }, + "data": { + "txs": null + }, + "evidence": { + "evidence": null + }, + "last_commit": { + "height": "9", + "round": 0, + "block_id": { + "hash": "760E050B2404A4BC661635CA552FF45876BCD927C367ADF88961E389C01D32FF", + "part_set_header": { + "total": 1, + "hash": "485070D01F9543827B3F9BAF11BDCFFBFD2BDED0B63D7192FA55649B94A1D5DE" + } + }, + "signatures": [ + { + "block_id_flag": 2, + "validator_address": "12CC3970B3AE9F19A4B1D98BE1799F2CB923E0A3", + "timestamp": "2020-03-15T16:57:08.151Z", + "signature": "GRBX/UNaf19vs5byJfAuXk2FQ05soOHmaMFCbrNBhHdNZtFKHp6J9eFwZrrG+YCxKMdqPn2tQWAes6X8kpd1DA==" + } + ] + } + } + } + ], + "total_count": "1" + } +} \ No newline at end of file diff --git a/rpc/tests/kvstore_fixtures/outgoing/block_search.json b/rpc/tests/kvstore_fixtures/outgoing/block_search.json new file mode 100644 index 000000000..91e1c9a82 --- /dev/null +++ b/rpc/tests/kvstore_fixtures/outgoing/block_search.json @@ -0,0 +1,11 @@ +{ + "id": "9ee74828-e8f1-429d-9d53-254c833bae00", + "jsonrpc": "2.0", + "method": "block_search", + "params": { + "order_by": "asc", + "page": "1", + "per_page": "10", + "query": "block.height > 1" + } +} \ No newline at end of file diff --git a/tools/kvstore-test/Makefile.toml b/tools/kvstore-test/Makefile.toml index a86c88dd5..7f811cd39 100644 --- a/tools/kvstore-test/Makefile.toml +++ b/tools/kvstore-test/Makefile.toml @@ -1,6 +1,6 @@ [env] CONTAINER_NAME = "kvstore-test" -DOCKER_IMAGE = "informaldev/tendermint:0.34.0" +DOCKER_IMAGE = "informaldev/tendermint:0.34.13" HOST_RPC_PORT = 26657 CARGO_MAKE_WAIT_MILLISECONDS = 1000 RUST_LOG = "debug" diff --git a/tools/kvstore-test/tests/tendermint.rs b/tools/kvstore-test/tests/tendermint.rs index 7cf01b6ed..38ddca661 100644 --- a/tools/kvstore-test/tests/tendermint.rs +++ b/tools/kvstore-test/tests/tendermint.rs @@ -138,6 +138,16 @@ mod rpc { assert!(block_results.txs_results.is_none()); } + /// `/block_search` endpoint + #[tokio::test] + async fn block_search() { + let res = localhost_http_client() + .block_search(Query::gt("block.height", 1), 1, 1, Order::Ascending) + .await + .unwrap(); + assert!(res.total_count > 0); + } + /// `/blockchain` endpoint #[tokio::test] async fn blockchain() { @@ -250,15 +260,21 @@ mod rpc { } async fn transaction_by_hash() { + let rpc_client = localhost_http_client(); + let (mut subs_client, driver) = localhost_websocket_client().await; + let driver_handle = tokio::spawn(async move { driver.run().await }); + let tx = Transaction::from(String::from("txtest=value").into_bytes()); - let r = localhost_http_client() - .broadcast_tx_commit(tx.clone()) + let (hash, _) = broadcast_tx(&rpc_client, &mut subs_client, tx.clone()) .await .unwrap(); - let hash = r.hash; + tokio::time::sleep(Duration::from_secs(1)).await; let r = localhost_http_client().tx(hash, false).await.unwrap(); assert_eq!(r.hash, hash); assert_eq!(r.tx, tx); + + subs_client.close().unwrap(); + let _ = driver_handle.await.unwrap(); } async fn simple_transaction_subscription() { @@ -395,7 +411,7 @@ mod rpc { let driver_handle = tokio::spawn(async move { driver.run().await }); let tx = "tx_search_key=tx_search_value".to_string(); - let tx_info = broadcast_tx( + let (_, tx_info) = broadcast_tx( &rpc_client, &mut subs_client, Transaction::from(tx.into_bytes()), @@ -404,9 +420,8 @@ mod rpc { .unwrap(); println!("Got tx_info: {:?}", tx_info); - // TODO(thane): Find a better way of accomplishing this. This might - // still be nondeterministic. - tokio::time::sleep(Duration::from_millis(500)).await; + // Give the indexer time to catch up + tokio::time::sleep(Duration::from_secs(1)).await; let res = rpc_client .tx_search( @@ -441,6 +456,8 @@ mod rpc { let r = client.broadcast_tx_commit(tx).await.unwrap(); let hash = r.hash; + tokio::time::sleep(Duration::from_secs(1)).await; + let r = client .tx_search( Query::from(EventType::Tx).and_eq("tx.hash", hash.to_string()), @@ -458,9 +475,9 @@ mod rpc { http_client: &HttpClient, websocket_client: &mut WebSocketClient, tx: Transaction, - ) -> Result { + ) -> Result<(tendermint::abci::transaction::Hash, TxInfo), tendermint_rpc::Error> { let mut subs = websocket_client.subscribe(EventType::Tx.into()).await?; - let _ = http_client.broadcast_tx_async(tx.clone()).await?; + let r = http_client.broadcast_tx_async(tx.clone()).await?; let timeout = tokio::time::sleep(Duration::from_secs(3)); tokio::pin!(timeout); @@ -473,7 +490,7 @@ mod rpc { let tx_result_bytes: &[u8] = tx_result.tx.as_ref(); // Make sure we have the right transaction here assert_eq!(tx.as_bytes(), tx_result_bytes); - Ok(tx_result) + Ok((r.hash, tx_result)) }, _ => panic!("Unexpected event: {:?}", ev), } diff --git a/tools/rpc-probe/Makefile.toml b/tools/rpc-probe/Makefile.toml index 1b21fabc1..ee1f5a6d4 100644 --- a/tools/rpc-probe/Makefile.toml +++ b/tools/rpc-probe/Makefile.toml @@ -1,6 +1,6 @@ [env] CONTAINER_NAME = "kvstore-rpc-probe" -DOCKER_IMAGE = "informaldev/tendermint:0.34.9" +DOCKER_IMAGE = "informaldev/tendermint:0.34.13" HOST_RPC_PORT = 26657 CARGO_MAKE_WAIT_MILLISECONDS = 3500 diff --git a/tools/rpc-probe/src/kvstore.rs b/tools/rpc-probe/src/kvstore.rs index cdc534170..a5f4b0eaf 100644 --- a/tools/rpc-probe/src/kvstore.rs +++ b/tools/rpc-probe/src/kvstore.rs @@ -30,6 +30,19 @@ pub fn block(height: u64) -> PlannedInteraction { .into() } +pub fn block_search(query: &str, page: u32, per_page: u32, order_by: &str) -> PlannedInteraction { + Request::new( + "block_search", + json!({ + "query": query, + "page": format!("{}", page), + "per_page": format!("{}", per_page), + "order_by": order_by, + }), + ) + .into() +} + pub fn block_results(height: u64) -> PlannedInteraction { Request::new( "block_results", diff --git a/tools/rpc-probe/src/quick.rs b/tools/rpc-probe/src/quick.rs index c3557b395..33df58aa9 100644 --- a/tools/rpc-probe/src/quick.rs +++ b/tools/rpc-probe/src/quick.rs @@ -21,6 +21,7 @@ pub fn quick_probe_plan(output_path: &Path, request_wait: Duration) -> Result 1", 1, 10, "asc").with_name("block_search"), blockchain(1, 10).with_name("blockchain_from_1_to_10"), commit(10).with_name("commit_at_height_10"), consensus_params(10), From 2c2f8141c07872f7d4d08e2327d3fb0524c93ab0 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 6 Oct 2021 09:54:15 +0200 Subject: [PATCH 12/16] Fix abci-test --- tools/abci-test/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/abci-test/Cargo.toml b/tools/abci-test/Cargo.toml index 62f4636f1..a41bcdf3f 100644 --- a/tools/abci-test/Cargo.toml +++ b/tools/abci-test/Cargo.toml @@ -14,6 +14,7 @@ description = """ futures = "0.3" structopt = "0.3" tendermint = { version = "0.22.0", path = "../../tendermint" } +tendermint-config = { version = "0.22.0", path = "../../config" } tendermint-rpc = { version = "0.22.0", path = "../../rpc", features = [ "websocket-client" ] } tracing = "0.1" tracing-subscriber = "0.2" From 4cf19e9eb10a1d23cbcfe8323725229c52b89680 Mon Sep 17 00:00:00 2001 From: Thane Thomson Date: Thu, 7 Oct 2021 17:02:14 -0400 Subject: [PATCH 13/16] Add changelog entry Signed-off-by: Thane Thomson --- .../unreleased/breaking-changes/983-tendermint-config.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .changelog/unreleased/breaking-changes/983-tendermint-config.md diff --git a/.changelog/unreleased/breaking-changes/983-tendermint-config.md b/.changelog/unreleased/breaking-changes/983-tendermint-config.md new file mode 100644 index 000000000..efd5e537e --- /dev/null +++ b/.changelog/unreleased/breaking-changes/983-tendermint-config.md @@ -0,0 +1,4 @@ +- `[tendermint, tendermint-config]` The `tendermint::config` + module has now been broken out into its own crate (`tendermint- + config`) to help towards facilitating `no_std` compatibility + ([#983](https://github.com/informalsystems/tendermint-rs/issues/983)) \ No newline at end of file From d00ad51da5b9b3800c23b251bc217de9fa1e1a72 Mon Sep 17 00:00:00 2001 From: Thane Thomson Date: Thu, 7 Oct 2021 17:11:24 -0400 Subject: [PATCH 14/16] Add more changelog entries for other breaking changes Signed-off-by: Thane Thomson --- .../unreleased/breaking-changes/983-tendermint-node-info.md | 4 ++++ .../breaking-changes/983-tendermint-node-listen-addr.md | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 .changelog/unreleased/breaking-changes/983-tendermint-node-info.md create mode 100644 .changelog/unreleased/breaking-changes/983-tendermint-node-listen-addr.md diff --git a/.changelog/unreleased/breaking-changes/983-tendermint-node-info.md b/.changelog/unreleased/breaking-changes/983-tendermint-node-info.md new file mode 100644 index 000000000..3ca391c1f --- /dev/null +++ b/.changelog/unreleased/breaking-changes/983-tendermint-node-info.md @@ -0,0 +1,4 @@ +- `[tendermint]` The `tendermint::node::info::OtherInfo::rpc_address` + field type has been changed from `tendermint::net::Address` + to `String` toward facilitating `no_std` compatibility + ([#983](https://github.com/informalsystems/tendermint-rs/issues/983)) \ No newline at end of file diff --git a/.changelog/unreleased/breaking-changes/983-tendermint-node-listen-addr.md b/.changelog/unreleased/breaking-changes/983-tendermint-node-listen-addr.md new file mode 100644 index 000000000..125bed986 --- /dev/null +++ b/.changelog/unreleased/breaking-changes/983-tendermint-node-listen-addr.md @@ -0,0 +1,4 @@ +- `[tendermint]` The `tendermint::node::info::ListenAddress::to_net_address` + method was replaced with a simple `as_str` method toward facilitating + `no_std` compatibility ([#983](https://github.com/informalsystems/tendermint- + rs/issues/983)) \ No newline at end of file From 12d67c95830d93236d129abbf3532074ecd9b60f Mon Sep 17 00:00:00 2001 From: Thane Thomson Date: Thu, 7 Oct 2021 17:12:32 -0400 Subject: [PATCH 15/16] Add tendermint-config to release script Signed-off-by: Thane Thomson --- release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.sh b/release.sh index 828815aab..8bf0ccc72 100755 --- a/release.sh +++ b/release.sh @@ -36,7 +36,7 @@ set -e # A space-separated list of all the crates we want to publish, in the order in # which they must be published. It's important to respect this order, since # each subsequent crate depends on one or more of the preceding ones. -DEFAULT_CRATES="tendermint-proto tendermint-std-ext tendermint tendermint-abci tendermint-rpc tendermint-p2p tendermint-light-client tendermint-light-client-js tendermint-testgen" +DEFAULT_CRATES="tendermint-proto tendermint-std-ext tendermint tendermint-config tendermint-abci tendermint-rpc tendermint-p2p tendermint-light-client tendermint-light-client-js tendermint-testgen" # Allows us to override the crates we want to publish. CRATES=${*:-${DEFAULT_CRATES}} From 097b434cd81788c23a07b1a5ae7cd00d629f8396 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 7 Oct 2021 23:50:25 +0200 Subject: [PATCH 16/16] Fix merge mistakes --- abci/Cargo.toml | 15 +++++++------- p2p/Cargo.toml | 30 ++++++++++++++-------------- p2p/src/error.rs | 10 +++++----- proto/Cargo.toml | 18 ++++++++--------- tendermint/Cargo.toml | 46 +++++++++++++++++++++---------------------- 5 files changed, 58 insertions(+), 61 deletions(-) diff --git a/abci/Cargo.toml b/abci/Cargo.toml index a590e9265..ef1524ba7 100644 --- a/abci/Cargo.toml +++ b/abci/Cargo.toml @@ -32,11 +32,10 @@ std = [ ] [dependencies] -bytes = "1.0" -prost = { package = "informalsystems-prost", version = "0.8.1" } -tendermint-proto = { version = "0.22.0", path = "../proto" } -tracing = "0.1" -flex-error = { version = "0.4.1", default-features = false } - -structopt = { version = "0.3", optional = true } -tracing-subscriber = { version = "0.2", optional = true } +bytes = { version = "1.0", default-features = false } +prost = { package = "informalsystems-prost", version = "0.8.1", default-features = false } +tendermint-proto = { version = "0.22.0", default-features = false, path = "../proto" } +tracing = { version = "0.1", default-features = false } +flex-error = { version = "0.4.3", default-features = false } +structopt = { version = "0.3", optional = true, default-features = false } +tracing-subscriber = { version = "0.2", optional = true, default-features = false } diff --git a/p2p/Cargo.toml b/p2p/Cargo.toml index 3a8bb167c..0a82b44b3 100644 --- a/p2p/Cargo.toml +++ b/p2p/Cargo.toml @@ -31,21 +31,21 @@ std = [ ] [dependencies] -chacha20poly1305 = "0.8" -ed25519-dalek = "1" -eyre = "0.6" -flume = "0.10.7" -hkdf = "0.10.0" -merlin = "2" -prost = { package = "informalsystems-prost", version = "0.8.1" } -rand_core = { version = "0.5", features = ["std"] } -sha2 = "0.9" -subtle = "2" -x25519-dalek = "1.1" -zeroize = "1" -signature = "1.3.0" -aead = "0.4.1" -flex-error = { version = "0.4.1", default-features = false } +chacha20poly1305 = { version = "0.8", default-features = false, features = ["reduced-round"] } +ed25519-dalek = { version = "1", default-features = false } +eyre = { version = "0.6", default-features = false } +flume = { version = "0.10.7", default-features = false } +hkdf = { version = "0.10.0", default-features = false } +merlin = { version = "2", default-features = false } +prost = { package = "informalsystems-prost", version = "0.8.1", default-features = false } +rand_core = { version = "0.5", default-features = false, features = ["std"] } +sha2 = { version = "0.9", default-features = false } +subtle = { version = "2", default-features = false } +x25519-dalek = { version = "1.1", default-features = false } +zeroize = { version = "1", default-features = false } +signature = { version = "1.3.0", default-features = false } +aead = { version = "0.4.1", default-features = false } +flex-error = { version = "0.4.3", default-features = false } # path dependencies tendermint = { path = "../tendermint", version = "0.22.0" } diff --git a/p2p/src/error.rs b/p2p/src/error.rs index 3a33aadbe..a0530c68d 100644 --- a/p2p/src/error.rs +++ b/p2p/src/error.rs @@ -1,6 +1,6 @@ //! Error types -use flex_error::{define_error, DisplayError, TraceError}; +use flex_error::{define_error, DisplayOnly}; use prost::DecodeError; use signature::Error as SignatureError; @@ -22,11 +22,11 @@ define_error! { | _ | { "malformed handshake message (protocol version mismatch?)" }, Io - [ TraceError ] + [ DisplayOnly ] | _ | { "io error" }, Decode - [ TraceError ] + [ DisplayOnly ] | _ | { "malformed handshake message (protocol version mismatch?)" }, MissingSecret @@ -36,14 +36,14 @@ define_error! { | _ | { "public key missing" }, Signature - [ TraceError ] + [ DisplayOnly ] | _ | { "signature error" }, UnsupportedKey | _ | { "secp256k1 is not supported" }, Aead - [ DisplayError ] + [ DisplayOnly ] | _ | { "aead error" }, ShortCiphertext diff --git a/proto/Cargo.toml b/proto/Cargo.toml index d385e1a92..b18c28b42 100644 --- a/proto/Cargo.toml +++ b/proto/Cargo.toml @@ -17,16 +17,16 @@ description = """ all-features = true [dependencies] -prost = { package = "informalsystems-prost", version = "0.8.1" } -prost-types = { package = "informalsystems-prost-types", version = "0.8.1" } -bytes = "1.0" -serde = { version = "1.0", features = ["derive"] } -subtle-encoding = "0.5" -serde_bytes = "0.11" -num-traits = "0.2" -num-derive = "0.3" +prost = { package = "informalsystems-prost", version = "0.8.1", default-features = false } +prost-types = { package = "informalsystems-prost-types", version = "0.8.1", default-features = false } +bytes = { version = "1.0", default-features = false } +serde = { version = "1.0", default-features = false, features = ["derive"] } +serde_bytes = { version = "0.11", default-features = false, features = ["alloc"] } +subtle-encoding = { version = "0.5", default-features = false, features = ["hex", "base64", "alloc"] } +num-traits = { version = "0.2", default-features = false } +num-derive = { version = "0.3", default-features = false } chrono = { version = "0.4", default-features = false, features = ["serde", "alloc"] } -flex-error = { version = "0.4.1", default-features = false } +flex-error = { version = "0.4.3", default-features = false } [dev-dependencies] serde_json = "1.0" diff --git a/tendermint/Cargo.toml b/tendermint/Cargo.toml index f1c0cb9ab..025f21c05 100644 --- a/tendermint/Cargo.toml +++ b/tendermint/Cargo.toml @@ -33,31 +33,29 @@ rustdoc-args = ["--cfg", "docsrs"] crate-type = ["cdylib", "rlib"] [dependencies] -async-trait = "0.1" -bytes = "1.0" -chrono = { version = "0.4.19", features = ["serde"] } -ed25519 = "1" -ed25519-dalek = { version = "1", features = ["serde"] } -futures = "0.3" -num-traits = "0.2" -once_cell = "1.3" -prost = { package = "informalsystems-prost", version = "0.8.1" } -prost-types = { package = "informalsystems-prost-types", version = "0.8.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -serde_bytes = "0.11" -serde_repr = "0.1" +async-trait = { version = "0.1", default-features = false } +bytes = { version = "1.0", default-features = false } +chrono = { version = "0.4.19", default-features = false, features = ["serde"] } +ed25519 = { version = "1", default-features = false } +ed25519-dalek = { version = "1", default-features = false, features = ["u64_backend"] } +futures = { version = "0.3", default-features = false } +num-traits = { version = "0.2", default-features = false } +once_cell = { version = "1.3", default-features = false } +prost = { package = "informalsystems-prost", version = "0.8.1", default-features = false } +prost-types = { package = "informalsystems-prost-types", version = "0.8.1", default-features = false } +serde = { version = "1", default-features = false, features = ["derive"] } +serde_json = { version = "1", default-features = false, features = ["alloc"] } +serde_bytes = { version = "0.11", default-features = false } +serde_repr = { version = "0.1", default-features = false } sha2 = { version = "0.9", default-features = false } -signature = "1.2" -subtle = "2" -subtle-encoding = { version = "0.5", features = ["bech32-preview"] } -tendermint-proto = { version = "0.22.0", path = "../proto" } -zeroize = { version = "1.1", features = ["zeroize_derive"] } -flex-error = { version = "0.4.1", default-features = false } -time = "0.1.40" - -k256 = { version = "0.9", optional = true, features = ["ecdsa"] } -ripemd160 = { version = "0.9", optional = true } +signature = { version = "1.2", default-features = false } +subtle = { version = "2", default-features = false } +subtle-encoding = { version = "0.5", default-features = false, features = ["bech32-preview"] } +tendermint-proto = { version = "0.22.0", default-features = false, path = "../proto" } +zeroize = { version = "1.1", default-features = false, features = ["zeroize_derive", "alloc"] } +flex-error = { version = "0.4.3", default-features = false } +k256 = { version = "0.9", optional = true, default-features = false, features = ["ecdsa", "sha256"] } +ripemd160 = { version = "0.9", default-features = false, optional = true } [features] default = ["std", "eyre_tracer"]