diff --git a/abci/Cargo.toml b/abci/Cargo.toml index 5efe1a9..7eaafeb 100644 --- a/abci/Cargo.toml +++ b/abci/Cargo.toml @@ -16,30 +16,38 @@ rust-version.workspace = true version.workspace = true [features] -default = [ - "server", - "docker-tests", - "crypto", - "tcp", - "unix", - "grpc", - "tracing-span", -] +# By default, include the server feature together with both tcp and unix transports. +default = ["server", "docker-tests", "crypto", "tcp", "unix", "tracing-span"] # docker-tests includes integration tests that require docker to be available docker-tests = ["server"] +# Enable server support; this is most likely what you want (plus `tcp` and/or `unix`) server = [ "tracing-subscriber/fmt", + "tenderdash-proto/server", "dep:tokio", "dep:tokio-util", "dep:futures", + "std", ] -# std is deprecated, use "grpc" instead -std = ["grpc"] -grpc = ["tenderdash-proto/grpc"] +# DEPRECATED; use `server` instead +grpc = ["server"] + +# Disable no_std support +std = ["tenderdash-proto/std"] + +# Include crypto features, like signature verification crypto = ["dep:lhash"] + +# Include server TCP support tcp = ["server"] + +# Include server unix socket support unix = ["server"] + +# Include `tracing` crate spans tracing-span = ["dep:uuid"] + +# Include `serde` support serde = ["tenderdash-proto/serde", "dep:serde_json"] [[example]] diff --git a/abci/src/lib.rs b/abci/src/lib.rs index 98d3abd..e1bab25 100644 --- a/abci/src/lib.rs +++ b/abci/src/lib.rs @@ -39,9 +39,9 @@ pub enum Error { #[error("connection error")] Connection(#[from] io::Error), #[error("cannot decode protobuf message")] - Decode(#[from] DecodeError), + Decode(DecodeError), #[error("cannot encode protobuf message")] - Encode(#[from] EncodeError), + Encode(EncodeError), #[error("cannot create canonical message: {0}")] Canonical(String), #[error("server terminated")] @@ -49,3 +49,17 @@ pub enum Error { #[error("async runtime error")] Async(String), } + +// manually implemented due to no_std compatibility +impl From for Error { + fn from(error: EncodeError) -> Error { + Error::Encode(error) + } +} + +// manually implemented due to no_std compatibility +impl From for Error { + fn from(error: DecodeError) -> Error { + Error::Decode(error) + } +} diff --git a/abci/src/server/generic.rs b/abci/src/server/generic.rs index 75b08d0..fd63d80 100644 --- a/abci/src/server/generic.rs +++ b/abci/src/server/generic.rs @@ -96,7 +96,7 @@ impl GenericServer { } } -impl<'a, App: RequestDispatcher + 'a, L: Listener> Server for GenericServer +impl Server for GenericServer where L: Listener + Send + Sync + 'static, L::Addr: Send + Debug, diff --git a/proto-compiler/Cargo.toml b/proto-compiler/Cargo.toml index cedec0c..cbd5dca 100644 --- a/proto-compiler/Cargo.toml +++ b/proto-compiler/Cargo.toml @@ -26,9 +26,4 @@ tonic-build = { version = "0.12.3", optional = true } [features] default = [] # Enable gRPC support; needed by server and client features. -# Conflicts with no_std grpc = ["dep:tonic-build"] -# Build the gRPC server. Requires tenderdash-proto/grpc feature. -server = ["grpc"] -# Build the gRPC client. Requires tenderdash-proto/grpc feature. -client = ["grpc"] diff --git a/proto-compiler/src/constants.rs b/proto-compiler/src/constants.rs index f5f7fec..d31d59d 100644 --- a/proto-compiler/src/constants.rs +++ b/proto-compiler/src/constants.rs @@ -1,5 +1,7 @@ //! Tenderdash protobuf implementation +use std::fmt::Display; + // Requirements pub const DEP_PROTOC_VERSION: f32 = 25.0; @@ -7,30 +9,36 @@ pub const DEP_PROTOC_VERSION: f32 = 25.0; pub const TENDERDASH_REPO: &str = "https://github.com/dashpay/tenderdash"; /// How to generate the protobuf files. - pub enum GenerationMode { /// Generate the files using `tonic` and put them into `tenderdash_grpc` /// module. - Grpc, + GrpcServer, + /// Generate minimal gRPC client using tonic, without transport + /// implementation. Put them into `tenderdash_grpc_client` module. + GrpcClient, /// Generate the files without `std` and put them into `tenderdash_nostd` /// module. NoStd, } + impl GenerationMode { pub fn module_name(&self) -> String { match self { - GenerationMode::Grpc => "tenderdash_grpc".to_string(), + GenerationMode::GrpcServer => "tenderdash_grpc".to_string(), + GenerationMode::GrpcClient => "tenderdash_grpc_client".to_string(), GenerationMode::NoStd => "tenderdash_nostd".to_string(), } } } -impl ToString for GenerationMode { - fn to_string(&self) -> String { - match self { - GenerationMode::Grpc => "tonic".to_string(), +impl Display for GenerationMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mode = match self { + GenerationMode::GrpcServer => "grpc-client-server".to_string(), + GenerationMode::GrpcClient => "grpc-client".to_string(), GenerationMode::NoStd => "nostd".to_string(), - } + }; + write!(f, "{}", mode) } } diff --git a/proto-compiler/src/functions.rs b/proto-compiler/src/functions.rs index 7016fbb..cd70592 100644 --- a/proto-compiler/src/functions.rs +++ b/proto-compiler/src/functions.rs @@ -311,7 +311,7 @@ pub mod meta {{ tenderdash_commitish(), abci_ver, td_ver, - mode.to_string(), + mode, ); let mut file = diff --git a/proto-compiler/src/lib.rs b/proto-compiler/src/lib.rs index fa21dfa..e0d237e 100644 --- a/proto-compiler/src/lib.rs +++ b/proto-compiler/src/lib.rs @@ -124,14 +124,29 @@ pub fn proto_compile(mode: GenerationMode) { println!("[info] => Creating structs."); match mode { - GenerationMode::Grpc => { + GenerationMode::GrpcServer => { #[cfg(feature = "grpc")] tonic_build::configure() + .build_client(true) + .build_server(true) + .build_transport(true) .generate_default_stubs(true) .compile_protos_with_config(pb, &protos, &proto_includes_paths) .unwrap(); #[cfg(not(feature = "grpc"))] - panic!("grpc feature is required to compile {}", mode.to_string()); + panic!("grpc feature is required to compile {}", mode); + }, + GenerationMode::GrpcClient => { + #[cfg(feature = "grpc")] + tonic_build::configure() + .build_client(true) + .build_server(false) + .build_transport(false) + .generate_default_stubs(true) + .compile_protos_with_config(pb, &protos, &proto_includes_paths) + .unwrap(); + #[cfg(not(feature = "grpc"))] + panic!("grpc feature is required to compile {}", mode); }, GenerationMode::NoStd => { pb.compile_protos(&protos, &proto_includes_paths).unwrap(); diff --git a/proto/Cargo.toml b/proto/Cargo.toml index 074f422..7ef35e5 100644 --- a/proto/Cargo.toml +++ b/proto/Cargo.toml @@ -34,16 +34,22 @@ all-features = true # # Sometimes cleaning the build cache with `cargo clean` might be necessary to solve # issues related to outdated generated files. -default = ["grpc"] +default = ["server"] -# Enable standard library support; DEPRECATED - use `grpc` instead -std = ["grpc"] -# Build gRPC server using tonic -grpc = [ +# Enable standard library support; required by `client` and `server` +std = ["client"] +# Enable gRPC support using tonic; DEPRECATED, consider using `server` or `client` instead +grpc = ["client"] +# Build gRPC server using tonic. Includes `client` feature. +server = ["client", "tonic/transport"] +# Build minimal gRPC client using tonic, without transport +client = [ + "tenderdash-proto-compiler/grpc", "prost/std", - "tenderdash-proto-compiler/server", - "tenderdash-proto-compiler/client", "dep:tonic", + "tonic/codegen", + "tonic/prost", + "std", ] serde = ["dep:serde", "bytes/serde"] @@ -53,7 +59,7 @@ bytes = { version = "1.7", default-features = false } prost = { version = "0.13", default-features = false, features = [ "prost-derive", ] } -tonic = { version = "0.12.3", optional = true } +tonic = { version = "0.12.3", optional = true, default-features = false } serde = { version = "1.0.208", default-features = false, features = [ "derive", ], optional = true } diff --git a/proto/build.rs b/proto/build.rs index f0a79ad..e14b3b4 100644 --- a/proto/build.rs +++ b/proto/build.rs @@ -13,8 +13,16 @@ fn main() { env::set_var("TENDERDASH_COMMITISH", DEFAULT_VERSION); } - #[cfg(feature = "grpc")] - tenderdash_proto_compiler::proto_compile(GenerationMode::Grpc); + // build gRPC server and client + // note it should be safe to build both server and client; we will just not use + // them in the lib.rs + + #[cfg(feature = "server")] + // build gRPC server (includes client) + tenderdash_proto_compiler::proto_compile(GenerationMode::GrpcServer); + #[cfg(feature = "client")] + // build gRPC client only + tenderdash_proto_compiler::proto_compile(GenerationMode::GrpcClient); // we always build nostd version tenderdash_proto_compiler::proto_compile(GenerationMode::NoStd); diff --git a/proto/src/.gitignore b/proto/src/.gitignore index 40ad867..032989a 100644 --- a/proto/src/.gitignore +++ b/proto/src/.gitignore @@ -1,5 +1,6 @@ tenderdash_nostd/ tenderdash_grpc/ +tenderdash_grpc_client/ # prost/ and tenderdash.rs are deprecated and can be removed in the future prost/ diff --git a/proto/src/error.rs b/proto/src/error.rs index ea92b87..9ef24ba 100644 --- a/proto/src/error.rs +++ b/proto/src/error.rs @@ -1,8 +1,8 @@ //! This module defines the various errors that be raised during Protobuf //! conversions. -#[cfg(not(feature = "grpc"))] +#[cfg(not(feature = "std"))] use core::{convert::TryFrom, fmt::Display, num::TryFromIntError}; -#[cfg(feature = "grpc")] +#[cfg(feature = "std")] use std::{fmt::Display, num::TryFromIntError}; use flex_error::{define_error, DisplayOnly}; diff --git a/proto/src/lib.rs b/proto/src/lib.rs index 399fa72..0b35a5d 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -1,9 +1,9 @@ //! tenderdash-proto library gives the developer access to the Tenderdash //! proto-defined structs. - -#![cfg_attr(not(feature = "grpc"), no_std)] +#![cfg_attr(not(feature = "std"), no_std)] #![deny(warnings, trivial_casts, trivial_numeric_casts, unused_import_braces)] #![allow(clippy::large_enum_variant)] +#![allow(clippy::doc_lazy_continuation)] #![forbid(unsafe_code)] extern crate alloc; @@ -21,29 +21,42 @@ pub mod google { mod error; -#[cfg(not(feature = "grpc"))] +#[cfg(not(feature = "std"))] use core::{ convert::{TryFrom, TryInto}, fmt::Display, }; -#[cfg(feature = "grpc")] +#[cfg(feature = "std")] use std::fmt::Display; use bytes::{Buf, BufMut}; pub use error::Error; pub use prost; use prost::{encoding::encoded_len_varint, Message}; + +#[cfg(not(any(feature = "server", feature = "client")))] #[rustfmt::skip] +#[allow(clippy::empty_docs)] pub mod tenderdash_nostd; -#[cfg(not(feature = "grpc"))] -// Re-export the nostd module only if the std one is not available -pub use tenderdash_nostd::*; -#[cfg(feature = "grpc")] +#[cfg(feature = "server")] #[rustfmt::skip] +#[allow(clippy::empty_docs)] pub mod tenderdash_grpc; -#[cfg(feature = "grpc")] +#[cfg(feature = "client")] +#[rustfmt::skip] +#[allow(clippy::empty_docs)] +pub mod tenderdash_grpc_client; + +// Now, re-export correct module + +#[cfg(feature = "server")] pub use tenderdash_grpc::*; +#[cfg(all(not(feature = "server"), feature = "client"))] +pub use tenderdash_grpc_client::*; +#[cfg(all(not(feature = "server"), not(feature = "client")))] +pub use tenderdash_nostd::*; + #[cfg(feature = "serde")] pub mod serializers; mod time; diff --git a/proto/src/prelude.rs b/proto/src/prelude.rs index 7fa30e1..24c0d3d 100644 --- a/proto/src/prelude.rs +++ b/proto/src/prelude.rs @@ -11,7 +11,7 @@ pub use alloc::{ }; pub use core::prelude::v1::*; -#[cfg(feature = "grpc")] +#[cfg(feature = "std")] pub use tonic; pub use crate::time::{FromMillis, ToMillis}; diff --git a/proto/src/protobuf.rs b/proto/src/protobuf.rs index c97a113..6d441d7 100644 --- a/proto/src/protobuf.rs +++ b/proto/src/protobuf.rs @@ -3,9 +3,9 @@ // Prost does not seem to have a way yet to remove documentations defined in // protobuf files. These structs are defined in gogoproto v1.3.1 at https://github.com/gogo/protobuf/tree/v1.3.1/protobuf/google/protobuf -#[cfg(not(feature = "grpc"))] +#[cfg(not(feature = "std"))] use core::fmt; -#[cfg(feature = "grpc")] +#[cfg(feature = "std")] use std::fmt; /// A Timestamp represents a point in time independent of any time zone or local diff --git a/proto/src/serializers/from_str.rs b/proto/src/serializers/from_str.rs index c1536ab..0544cc7 100644 --- a/proto/src/serializers/from_str.rs +++ b/proto/src/serializers/from_str.rs @@ -1,9 +1,9 @@ //! Serialize and deserialize any `T` that implements [[core::str::FromStr]] //! and [[core::fmt::Display]] from or into string. Note this can be used for //! all primitive data types. -#[cfg(not(feature = "grpc"))] +#[cfg(not(feature = "std"))] use core::{fmt::Display, str::FromStr}; -#[cfg(feature = "grpc")] +#[cfg(feature = "std")] use std::{fmt::Display, str::FromStr}; use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; diff --git a/proto/src/serializers/part_set_header_total.rs b/proto/src/serializers/part_set_header_total.rs index f55b977..17c9222 100644 --- a/proto/src/serializers/part_set_header_total.rs +++ b/proto/src/serializers/part_set_header_total.rs @@ -6,9 +6,9 @@ //! Tendermint Core v0.34.0. This deserializer allows backwards-compatibility by //! deserializing both ways. See also: -#[cfg(not(feature = "grpc"))] +#[cfg(not(feature = "std"))] use core::{convert::TryFrom, fmt::Formatter}; -#[cfg(feature = "grpc")] +#[cfg(feature = "std")] use std::fmt::Formatter; use serde::{ diff --git a/proto/src/serializers/time_duration.rs b/proto/src/serializers/time_duration.rs index 0bdc33a..f30e943 100644 --- a/proto/src/serializers/time_duration.rs +++ b/proto/src/serializers/time_duration.rs @@ -1,7 +1,7 @@ //! Serialize/deserialize core::time::Duration type from and into string: -#[cfg(not(feature = "grpc"))] +#[cfg(not(feature = "std"))] use core::time::Duration; -#[cfg(feature = "grpc")] +#[cfg(feature = "std")] use std::time::Duration; use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; diff --git a/proto/src/serializers/timestamp.rs b/proto/src/serializers/timestamp.rs index aa4af9c..5068736 100644 --- a/proto/src/serializers/timestamp.rs +++ b/proto/src/serializers/timestamp.rs @@ -1,7 +1,7 @@ //! Serialize/deserialize Timestamp type from and into string: -#[cfg(not(feature = "grpc"))] +#[cfg(not(feature = "std"))] use core::fmt::{self, Debug}; -#[cfg(feature = "grpc")] +#[cfg(feature = "std")] use std::fmt::{self, Debug}; use serde::{de::Error as _, ser::Error, Deserialize, Deserializer, Serialize, Serializer}; diff --git a/proto/src/time.rs b/proto/src/time.rs index 4ab3c18..ab0915c 100644 --- a/proto/src/time.rs +++ b/proto/src/time.rs @@ -1,9 +1,12 @@ //! Time conversion traits and functions +// Most likely we build nostd +#[cfg(not(any(feature = "server", feature = "client")))] +use crate::format; use crate::{google::protobuf::Timestamp, Error}; pub trait ToMillis { /// Convert protobuf timestamp into milliseconds since epoch - + /// /// Note there is a resolution difference, as timestamp uses nanoseconds /// /// # Arguments diff --git a/proto/tests/unit.rs b/proto/tests/unit.rs index ba59705..295297e 100644 --- a/proto/tests/unit.rs +++ b/proto/tests/unit.rs @@ -1,4 +1,4 @@ -#[cfg(not(feature = "grpc"))] +#[cfg(not(feature = "std"))] use core::convert::TryFrom; use tenderdash_proto::{