Skip to content

Commit

Permalink
feat(proto)!: serde feature to enable serde for all messages
Browse files Browse the repository at this point in the history
  • Loading branch information
lklimek committed Aug 30, 2024
1 parent 6b7e4f2 commit 1a1508a
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 84 deletions.
4 changes: 3 additions & 1 deletion abci/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
103 changes: 34 additions & 69 deletions proto-compiler/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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: <https://docs.rs/prost-build/0.6.1/prost_build/struct.Config.html#method.btree_map>
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)
Expand Down
4 changes: 4 additions & 0 deletions proto-compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion proto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
20 changes: 12 additions & 8 deletions proto/src/protobuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -62,7 +66,7 @@ pub struct Duration {
#[prost(int32, tag = "2")]
pub nanos: i32,
}

#[cfg(feature = "serde")]
impl serde::Serialize for Duration {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand All @@ -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;

Expand All @@ -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<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand Down
5 changes: 3 additions & 2 deletions proto/tests/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -136,6 +136,7 @@ pub fn test_response_exception_from() {
}

#[test]
#[cfg(feature = "serde")]
pub fn test_consensus_params_serde() {
let json = r#"
{
Expand Down Expand Up @@ -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();
}

0 comments on commit 1a1508a

Please sign in to comment.