Repository: informalsystems/tendermint-rs (language: rust)

Issue:
proto: `std` feature is broken
### What went wrong?

The `std` feature added in #1452 doesn't work. /cc @romac

### Steps to reproduce

```console
$ cd proto
$ cargo test --features std
```

This results in the following compile errors:

```
$ cargo test --features std                                                                                       130 ↵
   Compiling tendermint-proto v0.39.0 (/Users/tarcieri/src/tendermint-rs/proto)
error[E0433]: failed to resolve: use of undeclared crate or module `std`
   --> proto/src/google/protobuf/timestamp.rs:105:11
    |
105 | impl From<std::time::SystemTime> for Timestamp {
    |           ^^^ use of undeclared crate or module `std`

error[E0433]: failed to resolve: use of undeclared crate or module `std`
   --> proto/src/google/protobuf/timestamp.rs:106:26
    |
106 |     fn from(system_time: std::time::SystemTime) -> Timestamp {
    |                          ^^^ use of undeclared crate or module `std`

error[E0433]: failed to resolve: use of undeclared crate or module `std`
   --> proto/src/google/protobuf/timestamp.rs:107:65
    |
107 |         let (seconds, nanos) = match system_time.duration_since(std::time::UNIX_EPOCH) {
    |                                                                 ^^^ use of undeclared crate or module `std`

error[E0433]: failed to resolve: use of undeclared crate or module `std`
   --> proto/src/google/protobuf/timestamp.rs:155:29
    |
155 | impl TryFrom<Timestamp> for std::time::SystemTime {
    |                             ^^^ use of undeclared crate or module `std`
```

(truncated)

These errors don't occur when `cargo test --all-features` is used, hence why it wasn't caught by CI, ostensibly because when it's compiled with that some other crate is linking `std`.

It would be good in CI to explicitly test the `std` feature in isolation.

### Definition of "done"

`cargo test --features std` compiles in isolation.


Discussion / hints:

Fix patch:
diff --git a/.changelog/unreleased/bug-fixes/1454-fix-feature-flags.md b/.changelog/unreleased/bug-fixes/1454-fix-feature-flags.md
new file mode 100644
index 000000000..44bcb0138
--- /dev/null
+++ b/.changelog/unreleased/bug-fixes/1454-fix-feature-flags.md
@@ -0,0 +1,2 @@
+- Fix newly introduced `std` and `json-schema` features, and ensure all feature flag can be used independently and in isolation.
+  ([\#1454](https://github.com/informalsystems/tendermint-rs/issues/1454))
diff --git a/light-client/Cargo.toml b/light-client/Cargo.toml
index 9cd5685b7..fa05dc384 100644
--- a/light-client/Cargo.toml
+++ b/light-client/Cargo.toml
@@ -57,6 +57,7 @@ regex = { version = "1.7.3" }
 
 [dev-dependencies]
 tendermint-testgen = { path = "../testgen", default-features = false }
+tendermint-light-client-verifier = { version = "0.39.0", path = "../light-client-verifier", features = ["rust-crypto"] }
 
 serde_json = { version = "1.0.51", default-features = false }
 gumdrop = { version = "0.8.0", default-features = false }
diff --git a/proto/Cargo.toml b/proto/Cargo.toml
index 7aa970db4..5f6ab1986 100644
--- a/proto/Cargo.toml
+++ b/proto/Cargo.toml
@@ -17,8 +17,8 @@ description = """
 default = []
 std = []
 grpc = ["grpc-server"]
-grpc-server = ["dep:tonic"]
-json-schema = ["dep:schemars"]
+grpc-server = ["dep:tonic", "std"]
+json-schema = ["dep:schemars", "std"]
 borsh = ["dep:borsh"]
 parity-scale-codec = ["dep:parity-scale-codec", "dep:scale-info"]
 
diff --git a/proto/src/lib.rs b/proto/src/lib.rs
index 86cb6750a..f14887202 100644
--- a/proto/src/lib.rs
+++ b/proto/src/lib.rs
@@ -1,6 +1,6 @@
 //! tendermint-proto library gives the developer access to the Tendermint proto-defined structs.
 
-#![cfg_attr(not(any(feature = "grpc-server")), no_std)]
+#![cfg_attr(not(feature = "std"), no_std)]
 #![deny(warnings, trivial_casts, trivial_numeric_casts, unused_import_braces)]
 #![allow(clippy::large_enum_variant)]
 #![forbid(unsafe_code)]
diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml
index 3a0491135..998ce7ea2 100644
--- a/rpc/Cargo.toml
+++ b/rpc/Cargo.toml
@@ -29,7 +29,13 @@ path = "src/client/bin/main.rs"
 required-features = [ "cli" ]
 
 [features]
-default = ["flex-error/std", "flex-error/eyre_tracer"]
+default = [
+  "flex-error/std",
+  "flex-error/eyre_tracer"
+]
+secp256k1 = [
+  "tendermint/secp256k1"
+]
 cli = [
   "http-client",
   "structopt",
@@ -42,17 +48,20 @@ http-client = [
   "tokio/macros",
   "tracing"
 ]
-secp256k1 = [ "tendermint/secp256k1" ]
 websocket-client = [
   "async-tungstenite",
   "futures",
   "tokio/rt-multi-thread",
-  "tokio/fs",
   "tokio/macros",
   "tokio/sync",
   "tokio/time",
   "tracing"
 ]
+mock-client = [
+  "futures",
+  "tracing",
+  "tokio/macros"
+]
 
 [dependencies]
 tendermint = { version = "0.39.0", default-features = false, path = "../tendermint" }
@@ -92,3 +101,4 @@ tendermint = { version = "0.39.0", default-features = false, path = "../tendermi
 http = { version = "1", default-features = false, features = ["std"] }
 lazy_static = { version = "1.4.0", default-features = false }
 tokio-test = { version = "0.4", default-features = false }
+tokio = { version = "1.0", default-features = false, features = ["rt-multi-thread", "fs"] }
diff --git a/rpc/src/client.rs b/rpc/src/client.rs
index b073b47a8..dabb4f8dc 100644
--- a/rpc/src/client.rs
+++ b/rpc/src/client.rs
@@ -3,15 +3,31 @@
 mod compat;
 pub use compat::CompatMode;
 
-#[cfg(any(feature = "http-client", feature = "websocket-client"))]
+#[cfg(any(
+    feature = "http-client",
+    feature = "websocket-client",
+    feature = "mock-client"
+))]
 mod subscription;
-#[cfg(any(feature = "http-client", feature = "websocket-client"))]
+#[cfg(any(
+    feature = "http-client",
+    feature = "websocket-client",
+    feature = "mock-client"
+))]
 pub use subscription::{Subscription, SubscriptionClient};
 
-#[cfg(any(feature = "http-client", feature = "websocket-client"))]
+#[cfg(any(
+    feature = "http-client",
+    feature = "websocket-client",
+    feature = "mock-client"
+))]
 pub mod sync;
 
-#[cfg(any(feature = "http-client", feature = "websocket-client"))]
+#[cfg(any(
+    feature = "http-client",
+    feature = "websocket-client",
+    feature = "mock-client"
+))]
 mod transport;
 
 #[cfg(feature = "http-client")]
@@ -21,7 +37,7 @@ pub use transport::websocket::{
     self, WebSocketClient, WebSocketClientDriver, WebSocketClientUrl, WebSocketConfig,
 };
 
-#[cfg(any(feature = "http-client", feature = "websocket-client"))]
+#[cfg(feature = "mock-client")]
 pub use transport::mock::{MockClient, MockRequestMatcher, MockRequestMethodMatcher};
 
 use core::fmt;
diff --git a/rpc/src/client/subscription.rs b/rpc/src/client/subscription.rs
index 1686ebd67..afc054db6 100644
--- a/rpc/src/client/subscription.rs
+++ b/rpc/src/client/subscription.rs
@@ -90,7 +90,7 @@ impl Stream for Subscription {
 }
 
 impl Subscription {
-    pub(crate) fn new(id: String, query: Query, rx: SubscriptionRx) -> Self {
+    pub fn new(id: String, query: Query, rx: SubscriptionRx) -> Self {
         Self { id, query, rx }
     }
 
diff --git a/rpc/src/client/transport.rs b/rpc/src/client/transport.rs
index 3eb72ee5f..658fedd97 100644
--- a/rpc/src/client/transport.rs
+++ b/rpc/src/client/transport.rs
@@ -1,7 +1,6 @@
 //! Tendermint RPC client implementations for different transports.
 
 mod auth;
-pub mod mock;
 mod router;
 
 macro_rules! perform_with_compat {
@@ -24,5 +23,7 @@ macro_rules! perform_with_compat {
 
 #[cfg(feature = "http-client")]
 pub mod http;
+#[cfg(feature = "mock-client")]
+pub mod mock;
 #[cfg(feature = "websocket-client")]
 pub mod websocket;
diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs
index 1e8d05c28..6636c5078 100644
--- a/rpc/src/lib.rs
+++ b/rpc/src/lib.rs
@@ -34,13 +34,16 @@ mod prelude;
 
 pub mod client;
 
-#[cfg(any(feature = "http-client", feature = "websocket-client"))]
-pub use client::{
-    Client, MockClient, MockRequestMatcher, MockRequestMethodMatcher, Subscription,
-    SubscriptionClient,
-};
+#[cfg(any(
+    feature = "http-client",
+    feature = "websocket-client",
+    feature = "mock-client"
+))]
+pub use client::{Client, Subscription, SubscriptionClient};
 #[cfg(feature = "http-client")]
 pub use client::{HttpClient, HttpClientUrl};
+#[cfg(feature = "mock-client")]
+pub use client::{MockClient, MockRequestMatcher, MockRequestMethodMatcher};
 #[cfg(feature = "websocket-client")]
 pub use client::{WebSocketClient, WebSocketClientDriver, WebSocketClientUrl, WebSocketConfig};
 
diff --git a/tendermint/Cargo.toml b/tendermint/Cargo.toml
index fe24d374f..21c2ab9ce 100644
--- a/tendermint/Cargo.toml
+++ b/tendermint/Cargo.toml
@@ -57,8 +57,8 @@ ripemd = { version = "0.1.3", optional = true, default-features = false }
 default = ["std", "rust-crypto"]
 std = ["flex-error/std", "clock"]
 clock = ["time/std"]
-secp256k1 = ["k256", "ripemd"]
-rust-crypto = ["sha2", "ed25519-consensus"]
+secp256k1 = ["rust-crypto", "dep:k256", "dep:ripemd"]
+rust-crypto = ["dep:sha2", "dep:ed25519-consensus"]
 
 [dev-dependencies]
 k256 = { version = "0.13", default-features = false, features = ["ecdsa"] }


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index bea99c508..4aa3ef2c9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -34,32 +34,36 @@ jobs:
     steps:
       - uses: actions/checkout@v4
       - uses: dtolnay/rust-toolchain@stable
-      - run: cargo test-all-features -p tendermint
+      - uses: taiki-e/install-action@cargo-hack
+      - run: cargo test -p tendermint
+      - run: cargo hack test --each-feature -p tendermint
 
   tendermint-rpc:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
       - uses: dtolnay/rust-toolchain@stable
-      - run: cargo test-all-features -p tendermint-rpc
+      - uses: taiki-e/install-action@cargo-hack
+      - run: cargo test -p tendermint-rpc
+      - run: cargo hack test --each-feature -p tendermint-rpc
 
   tendermint-proto:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
       - uses: dtolnay/rust-toolchain@stable
-      - run: cargo test-all-features -p tendermint-proto
+      - uses: taiki-e/install-action@cargo-hack
+      - run: cargo test -p tendermint-proto
+      - run: cargo hack test --each-feature -p tendermint-proto
 
   tendermint-light-client:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
       - uses: dtolnay/rust-toolchain@stable
-      # NOTE: We test with default features to make sure things work without "unstable".
-      - name: Test with default features
-        run: cargo test -p tendermint-light-client
-      - name: Test with all features
-        run: cargo test-all-features -p tendermint-light-client
+      - uses: taiki-e/install-action@cargo-hack
+      - run: cargo test -p tendermint-light-client
+      - run: cargo hack test --each-feature -p tendermint-light-client
 
   # From https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/continuous-integration.html#github-actions
   tendermint-light-client-js: