diff --git a/abci/Cargo.toml b/abci/Cargo.toml index d5b5d18..95be52b 100644 --- a/abci/Cargo.toml +++ b/abci/Cargo.toml @@ -44,7 +44,9 @@ required-features = ["server"] [dependencies] uuid = { version = "1.8.0", features = ["v4", "fast-rng"], optional = true } -tenderdash-proto = { path = "../proto", default-features = false } +tenderdash-proto = { path = "../proto", default-features = false, features = [ + "serde", +] } bytes = { version = "1.6.0" } prost = { version = "0.12.4" } tracing = { version = "0.1.40", default-features = false } diff --git a/proto-compiler/src/constants.rs b/proto-compiler/src/constants.rs index eae86ce..be7f7f5 100644 --- a/proto-compiler/src/constants.rs +++ b/proto-compiler/src/constants.rs @@ -43,40 +43,46 @@ pub(crate) const DEFAULT_TENDERDASH_COMMITISH: &str = "v0.10-dev"; /// Predefined custom attributes for message annotations const PRIMITIVE_ENUM: &str = r#"#[derive(::num_derive::FromPrimitive, ::num_derive::ToPrimitive)]"#; -const SERIALIZED: &str = r#"#[derive(::serde::Deserialize, ::serde::Serialize)]"#; -const TYPE_TAG: &str = r#"#[serde(tag = "type", content = "value")]"#; +pub(crate) const SERIALIZED: &str = + r#"#[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]"#; +const TYPE_TAG: &str = r#"#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]"#; /// Predefined custom attributes for field annotations -const QUOTED: &str = r#"#[serde(with = "crate::serializers::from_str")]"#; -const QUOTED_WITH_DEFAULT: &str = r#"#[serde(with = "crate::serializers::from_str", default)]"#; -const DEFAULT: &str = r#"#[serde(default)]"#; -const HEXSTRING: &str = r#"#[serde(with = "crate::serializers::bytes::hexstring")]"#; -const BASE64STRING: &str = r#"#[serde(with = "crate::serializers::bytes::base64string")]"#; -const VEC_BASE64STRING: &str = r#"#[serde(with = "crate::serializers::bytes::vec_base64string")]"#; -const OPTIONAL: &str = r#"#[serde(with = "crate::serializers::optional")]"#; +const QUOTED: &str = + r#"#[cfg_attr(feature = "serde", serde(with = "crate::serializers::from_str"))]"#; +const QUOTED_WITH_DEFAULT: &str = + r#"#[cfg_attr(feature = "serde", serde(with = "crate::serializers::from_str", default))]"#; +const DEFAULT: &str = r#"#[cfg_attr(feature = "serde", serde(default))]"#; +const HEXSTRING: &str = + r#"#[cfg_attr(feature = "serde", serde(with = "crate::serializers::bytes::hexstring"))]"#; +const BASE64STRING: &str = + r#"#[cfg_attr(feature = "serde", serde(with = "crate::serializers::bytes::base64string"))]"#; +const VEC_BASE64STRING: &str = r#"#[cfg_attr(feature = "serde", serde(with = "crate::serializers::bytes::vec_base64string"))]"#; +const OPTIONAL: &str = + r#"#[cfg_attr(feature = "serde", serde(with = "crate::serializers::optional"))]"#; // const BYTES_SKIP_IF_EMPTY: &str = r#"#[serde(skip_serializing_if = // "bytes::Bytes::is_empty")]"#; const DERIVE_FROM_FORWARD: &str = r#"#[from(forward)]"#; -const NULLABLEVECARRAY: &str = r#"#[serde(with = "crate::serializers::txs")]"#; -const NULLABLE: &str = r#"#[serde(with = "crate::serializers::nullable")]"#; -const ALIAS_POWER_QUOTED: &str = - r#"#[serde(alias = "power", with = "crate::serializers::from_str")]"#; +const NULLABLEVECARRAY: &str = + r#"#[cfg_attr(feature = "serde", serde(with = "crate::serializers::txs"))]"#; +const NULLABLE: &str = + r#"#[cfg_attr(feature = "serde", serde(with = "crate::serializers::nullable"))]"#; +const ALIAS_POWER_QUOTED: &str = r#"#[cfg_attr(feature = "serde", serde(alias = "power", with = "crate::serializers::from_str"))]"#; const PART_SET_HEADER_TOTAL: &str = - r#"#[serde(with = "crate::serializers::part_set_header_total")]"#; -const RENAME_EDPUBKEY: &str = r#"#[serde(rename = "tenderdash/PubKeyEd25519", with = "crate::serializers::bytes::base64string")]"#; -const RENAME_SECPPUBKEY: &str = r#"#[serde(rename = "tenderdash/PubKeySecp256k1", with = "crate::serializers::bytes::base64string")]"#; -const RENAME_SRPUBKEY: &str = r#"#[serde(rename = "tenderdash/PubKeySr25519", with = "crate::serializers::bytes::base64string")]"#; -const RENAME_DUPLICATEVOTE: &str = r#"#[serde(rename = "tenderdash/DuplicateVoteEvidence")]"#; + r#"#[cfg_attr(feature = "serde", serde(with = "crate::serializers::part_set_header_total"))]"#; +const RENAME_EDPUBKEY: &str = r#"#[cfg_attr(feature = "serde", serde(rename = "tenderdash/PubKeyEd25519", with = "crate::serializers::bytes::base64string"))]"#; +const RENAME_SECPPUBKEY: &str = r#"#[cfg_attr(feature = "serde", serde(rename = "tenderdash/PubKeySecp256k1", with = "crate::serializers::bytes::base64string"))]"#; +const RENAME_SRPUBKEY: &str = r#"#[cfg_attr(feature = "serde", serde(rename = "tenderdash/PubKeySr25519", with = "crate::serializers::bytes::base64string"))]"#; +const RENAME_DUPLICATEVOTE: &str = + r#"#[cfg_attr(feature = "serde", serde(rename = "tenderdash/DuplicateVoteEvidence"))]"#; const RENAME_LIGHTCLIENTATTACK: &str = - r#"#[serde(rename = "tenderdash/LightClientAttackEvidence")]"#; + r#"#[cfg_attr(feature = "serde", serde(rename = "tenderdash/LightClientAttackEvidence"))]"#; // const EVIDENCE_VARIANT: &str = r#"#[serde(from = // "crate::serializers::evidence::EvidenceVariant", // into = "crate::serializers::evidence::EvidenceVariant")]"#; -const ALIAS_VALIDATOR_POWER_QUOTED: &str = - r#"#[serde(alias = "ValidatorPower", with = "crate::serializers::from_str")]"#; -const ALIAS_TOTAL_VOTING_POWER_QUOTED: &str = - r#"#[serde(alias = "TotalVotingPower", with = "crate::serializers::from_str")]"#; -const ALIAS_TIMESTAMP: &str = r#"#[serde(alias = "Timestamp")]"#; -const ALIAS_PARTS: &str = r#"#[serde(alias = "parts")]"#; +const ALIAS_VALIDATOR_POWER_QUOTED: &str = r#"#[cfg_attr(feature = "serde", serde(alias = "ValidatorPower", with = "crate::serializers::from_str"))]"#; +const ALIAS_TOTAL_VOTING_POWER_QUOTED: &str = r#"#[cfg_attr(feature = "serde", serde(alias = "TotalVotingPower", with = "crate::serializers::from_str"))]"#; +const ALIAS_TIMESTAMP: &str = r#"#[cfg_attr(feature = "serde", serde(alias = "Timestamp"))]"#; +const ALIAS_PARTS: &str = r#"#[cfg_attr(feature = "serde", serde(alias = "parts"))]"#; const DERIVE_FROM: &str = r#"#[derive(derive_more::From)]"#; const DERIVE_FROM_STR: &str = r#"#[derive(derive_more::FromStr)]"#; /// Custom type attributes applied on top of protobuf structs @@ -85,54 +91,13 @@ const DERIVE_FROM_STR: &str = r#"#[derive(derive_more::FromStr)]"#; /// The first item is a path as defined in the prost_build::Config::btree_map /// here: pub static CUSTOM_TYPE_ATTRIBUTES: &[(&str, &str)] = &[ - (".tendermint.abci.Event", SERIALIZED), - (".tendermint.abci.EventAttribute", SERIALIZED), - (".tendermint.libs.bits.BitArray", SERIALIZED), - (".tendermint.types.BlockIDFlag", PRIMITIVE_ENUM), - (".tendermint.types.Block", SERIALIZED), - (".tendermint.types.Data", SERIALIZED), - (".tendermint.types.EvidenceList", SERIALIZED), - (".tendermint.types.Evidence", SERIALIZED), - (".tendermint.types.EvidenceVariant", SERIALIZED), - (".tendermint.types.DuplicateVoteEvidence", SERIALIZED), - (".tendermint.types.Vote", SERIALIZED), - (".tendermint.types.BlockID", SERIALIZED), - (".tendermint.types.PartSetHeader", SERIALIZED), - (".tendermint.types.LightClientAttackEvidence", SERIALIZED), - (".tendermint.types.LightBlock", SERIALIZED), - (".tendermint.types.SignedHeader", SERIALIZED), - (".tendermint.types.Header", SERIALIZED), - (".tendermint.version.Consensus", SERIALIZED), - (".tendermint.types.Commit", SERIALIZED), - (".tendermint.types.CommitSig", SERIALIZED), - (".tendermint.types.CoreChainLock", SERIALIZED), - (".tendermint.types.ValidatorSet", SERIALIZED), - (".tendermint.crypto.PublicKey", SERIALIZED), (".tendermint.crypto.PublicKey.sum", TYPE_TAG), + (".tendermint.types.BlockIDFlag", PRIMITIVE_ENUM), (".tendermint.types.Evidence.sum", TYPE_TAG), - (".tendermint.abci.ResponseInfo", SERIALIZED), + (".tendermint.abci.Request.value", DERIVE_FROM), + (".tendermint.abci.Response.value", DERIVE_FROM), (".tendermint.abci.ResponseException", DERIVE_FROM), (".tendermint.abci.ResponseException", DERIVE_FROM_STR), - (".tendermint.types.CanonicalBlockID", SERIALIZED), - (".tendermint.types.CanonicalPartSetHeader", SERIALIZED), - (".tendermint.types.Validator", SERIALIZED), - (".tendermint.types.CanonicalVote", SERIALIZED), - (".tendermint.types.VoteExtension", SERIALIZED), - (".tendermint.types.BlockMeta", SERIALIZED), - // (".tendermint.types.Evidence", EVIDENCE_VARIANT), - (".tendermint.types.TxProof", SERIALIZED), - (".tendermint.crypto.Proof", SERIALIZED), - (".tendermint.abci.Response.value", DERIVE_FROM), - (".tendermint.abci.Request.value", DERIVE_FROM), - // Consensus params - (".tendermint.types.ConsensusParams", SERIALIZED), - (".tendermint.types.ABCIParams", SERIALIZED), - (".tendermint.types.BlockParams", SERIALIZED), - (".tendermint.types.EvidenceParams", SERIALIZED), - (".tendermint.types.ValidatorParams", SERIALIZED), - (".tendermint.types.VersionParams", SERIALIZED), - (".tendermint.types.SynchronyParams", SERIALIZED), - (".tendermint.types.TimeoutParams", SERIALIZED), ]; /// Custom field attributes applied on top of protobuf fields in (a) struct(s) diff --git a/proto-compiler/src/lib.rs b/proto-compiler/src/lib.rs index 8a411e7..a36a4e1 100644 --- a/proto-compiler/src/lib.rs +++ b/proto-compiler/src/lib.rs @@ -95,10 +95,14 @@ pub fn proto_compile(mode: GenerationMode) { // Compile proto files with added annotations, exchange prost_types to our own pb.out_dir(&out_dir); + pb.type_attribute(".", constants::SERIALIZED); for type_attribute in CUSTOM_TYPE_ATTRIBUTES { + println!("[info] => Adding type attribute: {:?}", type_attribute); pb.type_attribute(type_attribute.0, type_attribute.1); } + for field_attribute in CUSTOM_FIELD_ATTRIBUTES { + println!("[info] => Adding field attribute: {:?}", field_attribute); pb.field_attribute(field_attribute.0, field_attribute.1); } // The below in-place path redirection replaces references to the Duration diff --git a/proto/Cargo.toml b/proto/Cargo.toml index 83c6bcb..9567495 100644 --- a/proto/Cargo.toml +++ b/proto/Cargo.toml @@ -31,7 +31,7 @@ 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 = ["grpc", "serde"] # Enable standard library support; DEPRECATED - use `grpc` instead std = ["grpc"] @@ -43,13 +43,17 @@ grpc = [ "dep:tonic", ] +serde = ["dep:serde", "bytes/serde"] + [dependencies] +bytes = { version = "1.6.0", default-features = false } prost = { version = "0.12.4", default-features = false, features = [ "prost-derive", ] } tonic = { version = "0.11.0", optional = true } -bytes = { version = "1.6.0", default-features = false, features = ["serde"] } -serde = { version = "1.0.197", default-features = false, features = ["derive"] } +serde = { version = "1.0.197", default-features = false, features = [ + "derive", +], optional = true } subtle-encoding = { version = "0.5.1", default-features = false, features = [ "hex", "base64", diff --git a/proto/src/lib.rs b/proto/src/lib.rs index 1ba8069..b14fc93 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -43,7 +43,7 @@ pub use tenderdash_nostd::*; pub mod tenderdash_grpc; #[cfg(feature = "grpc")] pub use tenderdash_grpc::*; - +#[cfg(feature = "serde")] pub mod serializers; mod time; diff --git a/proto/src/protobuf.rs b/proto/src/protobuf.rs index 04237ac..fa6b8bb 100644 --- a/proto/src/protobuf.rs +++ b/proto/src/protobuf.rs @@ -21,10 +21,14 @@ use std::fmt; /// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By /// restricting to that range, we ensure that we can convert to and from [RFC /// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. -#[derive(Clone, PartialEq, ::prost::Message, ::serde::Deserialize, ::serde::Serialize)] -#[serde( - from = "crate::serializers::timestamp::Rfc3339", - into = "crate::serializers::timestamp::Rfc3339" +#[derive(Clone, PartialEq, ::prost::Message)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[cfg_attr( + feature = "serde", + serde( + from = "crate::serializers::timestamp::Rfc3339", + into = "crate::serializers::timestamp::Rfc3339" + ) )] pub struct Timestamp { /// Represents seconds of UTC time since Unix epoch @@ -62,7 +66,7 @@ pub struct Duration { #[prost(int32, tag = "2")] pub nanos: i32, } - +#[cfg(feature = "serde")] impl serde::Serialize for Duration { fn serialize(&self, serializer: S) -> Result where @@ -72,9 +76,9 @@ impl serde::Serialize for Duration { serializer.serialize_i64(total_nanos) } } - +#[cfg(feature = "serde")] struct DurationVisitor; - +#[cfg(feature = "serde")] impl<'de> serde::de::Visitor<'de> for DurationVisitor { type Value = Duration; @@ -99,7 +103,7 @@ impl<'de> serde::de::Visitor<'de> for DurationVisitor { self.visit_i128(value) } } - +#[cfg(feature = "serde")] impl<'de> serde::Deserialize<'de> for Duration { fn deserialize(deserializer: D) -> Result where diff --git a/proto/tests/unit.rs b/proto/tests/unit.rs index 229c353..cf0edfc 100644 --- a/proto/tests/unit.rs +++ b/proto/tests/unit.rs @@ -3,7 +3,7 @@ use core::convert::TryFrom; use tenderdash_proto::{ abci::ResponseException, - types::{BlockId as RawBlockId, ConsensusParams, PartSetHeader as RawPartSetHeader}, + types::{BlockId as RawBlockId, PartSetHeader as RawPartSetHeader}, Protobuf, }; @@ -136,6 +136,7 @@ pub fn test_response_exception_from() { } #[test] +#[cfg(feature = "serde")] pub fn test_consensus_params_serde() { let json = r#" { @@ -173,5 +174,5 @@ pub fn test_consensus_params_serde() { } "#; - let _new_params: ConsensusParams = serde_json::from_str(json).unwrap(); + let _new_params: tenderdash_proto::types::ConsensusParams = serde_json::from_str(json).unwrap(); }