Skip to content

Commit

Permalink
explicit deny_unknown_fields
Browse files Browse the repository at this point in the history
  • Loading branch information
pompon0 committed Sep 25, 2024
1 parent 42992b5 commit ff3de8c
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 69 deletions.
24 changes: 12 additions & 12 deletions node/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions node/libs/protobuf/examples/conformance_test/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ mod proto;
/// Decodes a generated proto message from json for arbitrary ReflectMessage.
fn decode_json_proto<T: ReflectMessage + Default>(json: &str) -> anyhow::Result<T> {
let mut deserializer = serde_json::Deserializer::from_str(json);
let proto: T = zksync_protobuf::serde::deserialize_proto(&mut deserializer)?;
let proto: T = zksync_protobuf::serde::Deserialize{deny_unknown_fields:true}.proto(&mut deserializer)?;
deserializer.end()?;
Ok(proto)
}

/// Encodes a generated proto message to json for arbitrary ReflectMessage.
fn encode_json_proto<T: ReflectMessage>(proto: &T) -> String {
let mut serializer = serde_json::Serializer::pretty(vec![]);
zksync_protobuf::serde::serialize_proto(proto, &mut serializer).unwrap();
zksync_protobuf::serde::Serialize{}.proto(proto, &mut serializer).unwrap();
String::from_utf8(serializer.into_inner()).unwrap()
}

Expand Down
144 changes: 106 additions & 38 deletions node/libs/protobuf/src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,132 @@
//! therefore it is suitable for version control.
//! WARNING: Currently this serde implementation uses reflection,
//! so it is not very efficient.
use crate::ProtoFmt;
use crate::{ProtoFmt,ProtoRepr};
use prost::Message as _;
use prost_reflect::ReflectMessage;

/*
/// ProtoFmt wrapper which implements serde Serialize/Deserialize.
#[derive(Debug, Clone)]
pub struct Serde<T>(pub T);
impl<T: ProtoFmt> serde::Serialize for Serde<T> {
impl<T: ProtoFmt, const X :Deserialize> serde::Serialize for Serde<T,X> {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize(&self.0, s)
}
}
impl<'de, T: ProtoFmt> serde::Deserialize<'de> for Serde<T> {
impl<'de, T: ProtoFmt, const X :Deserialize> serde::Deserialize<'de> for Serde<T,X> {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(Self(deserialize(d)?))
Ok(Self(X.deserialize(d)?))
}
}
*/

/// Implementation of serde::Serialize for arbitrary ReflectMessage.
pub fn serialize_proto<T: ReflectMessage, S: serde::Serializer>(
x: &T,
s: S,
) -> Result<S::Ok, S::Error> {
let opts = prost_reflect::SerializeOptions::new();
x.transcode_to_dynamic().serialize_with_options(s, &opts)
}
/// Serialization options.
pub struct Serialize {}

/// Implementation of serde::Serialize for arbitrary ProtoFmt.
pub fn serialize<T: ProtoFmt, S: serde::Serializer>(x: &T, s: S) -> Result<S::Ok, S::Error> {
serialize_proto(&x.build(), s)
}
impl Serialize {
/// Serializes ReflectMessage.
pub fn proto<T: ReflectMessage, S: serde::Serializer>(
&self,
x: &T,
s: S,
) -> Result<S::Ok, S::Error> {
let opts = prost_reflect::SerializeOptions::new();
x.transcode_to_dynamic().serialize_with_options(s, &opts)
}

/// Serializes ProtoFmt.
pub fn proto_fmt<T: ProtoFmt, S: serde::Serializer>(&self, x: &T, s: S) -> Result<S::Ok, S::Error> {
self.proto(&x.build(), s)
}

/// Serializes ProtoFmt to json.
pub fn proto_fmt_to_json<T: ProtoFmt>(&self, x: &T) -> String {
let mut s = serde_json::Serializer::pretty(vec![]);
self.proto_fmt(x, &mut s).unwrap();
String::from_utf8(s.into_inner()).unwrap()
}

/// Implementation of serde::Deserialize for arbitrary ReflectMessage denying unknown fields
pub fn deserialize_proto<'de, T: ReflectMessage + Default, D: serde::Deserializer<'de>>(
d: D,
) -> Result<T, D::Error> {
deserialize_proto_with_options(d, true)
/// Serializes ProtoFmt to yaml
pub fn proto_fmt_to_yaml<T: ProtoFmt>(&self, x: &T) -> String {
let mut s = serde_yaml::Serializer::new(vec![]);
self.proto_fmt(x, &mut s).unwrap();
String::from_utf8(s.into_inner().unwrap()).unwrap()
}

/// Serializes ProtoRepr.
pub fn proto_repr<T: ProtoRepr, S: serde::Serializer>(&self, x: &T::Type, s: S) -> Result<S::Ok, S::Error> {
self.proto(&T::build(x), s)
}

/// Serializes ProtoRepr to json.
pub fn proto_repr_to_json<T: ProtoRepr>(&self, x: &T::Type) -> String {
let mut s = serde_json::Serializer::pretty(vec![]);
self.proto_repr::<T,_>(x, &mut s).unwrap();
String::from_utf8(s.into_inner()).unwrap()
}

/// Serializes ProtoRepr to yaml
pub fn proto_repr_to_yaml<T: ProtoRepr>(&self, x: &T::Type) -> String {
let mut s = serde_yaml::Serializer::new(vec![]);
self.proto_repr::<T,_>(x, &mut s).unwrap();
String::from_utf8(s.into_inner().unwrap()).unwrap()
}
}

/// Implementation of serde::Deserialize for arbitrary ReflectMessage with deny_unknown_fields option
pub fn deserialize_proto_with_options<
'de,
T: ReflectMessage + Default,
D: serde::Deserializer<'de>,
>(
d: D,
deny_unknown_fields: bool,
) -> Result<T, D::Error> {
let mut p = T::default();
let options = prost_reflect::DeserializeOptions::new().deny_unknown_fields(deny_unknown_fields);
let msg = prost_reflect::DynamicMessage::deserialize_with_options(p.descriptor(), d, &options)?;
p.merge(msg.encode_to_vec().as_slice()).unwrap();
Ok(p)
/// Deserialization options.
#[derive(Default)]
pub struct Deserialize {
/// true => returns an error when an unknown field is found.
/// false => silently ignores unknown fields.
pub deny_unknown_fields: bool
}

/// Implementation of serde::Deserialize for arbitrary ProtoFmt.
pub fn deserialize<'de, T: ProtoFmt, D: serde::Deserializer<'de>>(d: D) -> Result<T, D::Error> {
T::read(&deserialize_proto(d)?).map_err(serde::de::Error::custom)
impl Deserialize {
/// Implementation of serde::Deserialize for arbitrary ReflectMessage with deny_unknown_fields option
pub fn proto<'de, T: ReflectMessage + Default, D: serde::Deserializer<'de>>(&self, d: D) -> Result<T, D::Error> {
let mut p = T::default();
let options = prost_reflect::DeserializeOptions::new().deny_unknown_fields(self.deny_unknown_fields);
let msg = prost_reflect::DynamicMessage::deserialize_with_options(p.descriptor(), d, &options)?;
p.merge(msg.encode_to_vec().as_slice()).unwrap();
Ok(p)
}

/// Implementation of serde::Deserialize for arbitrary ProtoFmt.
pub fn proto_fmt<'de, T: ProtoFmt, D: serde::Deserializer<'de>>(&self, d: D) -> Result<T, D::Error> {
T::read(&self.proto(d)?).map_err(serde::de::Error::custom)
}

/// Deserializes ProtoFmt from json.
pub fn proto_fmt_from_json<T: ProtoFmt>(&self, json: &str) -> anyhow::Result<T> {
let mut d = serde_json::Deserializer::from_str(json);
let p = self.proto_fmt(&mut d)?;
d.end()?;
Ok(p)
}

/// Deserializes ProtoFmt from yaml.
pub fn proto_fmt_from_yaml<T: ProtoFmt>(&self, yaml: &str) -> anyhow::Result<T> {
Ok(self.proto_fmt(serde_yaml::Deserializer::from_str(yaml))?)
}

/// Implementation of serde::Deserialize for arbitrary ProtoFmt.
pub fn proto_repr<'de, T: ProtoRepr, D: serde::Deserializer<'de>>(&self, d: D) -> Result<T::Type, D::Error> {
self.proto::<T,D>(d)?.read().map_err(serde::de::Error::custom)
}

/// Deserializes ProtoRepr from json.
pub fn proto_repr_from_json<T: ProtoRepr>(&self, json: &str) -> anyhow::Result<T::Type> {
let mut d = serde_json::Deserializer::from_str(json);
let p = self.proto_repr::<T,_>(&mut d)?;
d.end()?;
Ok(p)
}

/// Deserializes ProtoRepr from yaml.
pub fn proto_repr_from_yaml<T: ProtoRepr>(&self, yaml: &str) -> anyhow::Result<T::Type> {
Ok(self.proto_repr::<T,_>(serde_yaml::Deserializer::from_str(yaml))?)
}
}
10 changes: 5 additions & 5 deletions node/libs/protobuf/src/testonly/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Testonly utilities.
use super::{canonical, canonical_raw, decode, encode, read_fields, ProtoFmt, ProtoRepr, Wire};
use super::{serde::{Serialize,Deserialize}, canonical, canonical_raw, decode, encode, read_fields, ProtoFmt, ProtoRepr, Wire};
use prost::Message as _;
use prost_reflect::ReflectMessage;
use rand::{
Expand Down Expand Up @@ -114,24 +114,24 @@ fn decode_proto<X: ProtoConv>(bytes: &[u8]) -> anyhow::Result<X::Type> {

fn encode_json<X: ProtoConv>(msg: &X::Type) -> String {
let mut s = serde_json::Serializer::pretty(vec![]);
crate::serde::serialize_proto(&X::build(msg), &mut s).unwrap();
Serialize{}.proto(&X::build(msg), &mut s).unwrap();
String::from_utf8(s.into_inner()).unwrap()
}

fn decode_json<X: ProtoConv>(json: &str) -> anyhow::Result<X::Type> {
let mut d = serde_json::Deserializer::from_str(json);
X::read(&crate::serde::deserialize_proto(&mut d)?)
X::read(&Deserialize{deny_unknown_fields:true}.proto(&mut d)?)
}

fn encode_yaml<X: ProtoConv>(msg: &X::Type) -> String {
let mut s = serde_yaml::Serializer::new(vec![]);
crate::serde::serialize_proto(&X::build(msg), &mut s).unwrap();
Serialize{}.proto(&X::build(msg), &mut s).unwrap();
String::from_utf8(s.into_inner().unwrap()).unwrap()
}

fn decode_yaml<X: ProtoConv>(yaml: &str) -> anyhow::Result<X::Type> {
let d = serde_yaml::Deserializer::from_str(yaml);
X::read(&crate::serde::deserialize_proto(d)?)
X::read(&Deserialize{deny_unknown_fields:true}.proto(d)?)
}

/// Wrapper for `ProtoRepr`, implementing ProtoConv;
Expand Down
4 changes: 2 additions & 2 deletions node/tools/src/bin/localnet_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{
};
use zksync_consensus_roles::{node, validator};
use zksync_consensus_tools::config;
use zksync_protobuf::serde::Serde;
use zksync_protobuf::serde::{Serialize};

/// Command line arguments.
#[derive(Debug, Parser)]
Expand Down Expand Up @@ -111,7 +111,7 @@ fn main() -> anyhow::Result<()> {
.context("fs::set_permissions()")?;

let config_path = root.join("config.json");
fs::write(&config_path, config::encode_json(&Serde(cfg))).context("fs::write()")?;
fs::write(&config_path, Serialize{}.proto_fmt_to_json(&cfg)).context("fs::write()")?;
fs::set_permissions(&config_path, Permissions::from_mode(0o600))
.context("fs::set_permissions()")?;
}
Expand Down
2 changes: 1 addition & 1 deletion node/tools/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn read_optional_secret_text<T: TextFmt>(text: &Option<String>) -> anyhow::Resul
/// Ports for the nodes to listen on kubernetes pod.
pub const NODES_PORT: u16 = 3054;

/// Decodes a proto message from json for arbitrary ProtoFmt.
/// Decodes serde type from json.
pub fn decode_json<T: serde::de::DeserializeOwned>(json: &str) -> anyhow::Result<T> {
let mut d = serde_json::Deserializer::from_str(json);
let p = T::deserialize(&mut d)?;
Expand Down
7 changes: 2 additions & 5 deletions node/tools/src/k8s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use kube::{
use std::{collections::BTreeMap, net::SocketAddr, time::Duration};
use tokio::time;
use tracing::log::info;
use zksync_protobuf::serde::Serde;
use zksync_protobuf::serde::{Serialize};

/// Docker image name for consensus nodes.
const DOCKER_IMAGE_NAME: &str = "consensus-node";
Expand Down Expand Up @@ -335,10 +335,7 @@ fn is_pod_running(pod: &Pod) -> bool {
fn get_cli_args(consensus_node: &ConsensusNode) -> Vec<String> {
vec![
"--config".to_string(),
config::encode_with_serializer(
&Serde(consensus_node.config.clone()),
serde_json::Serializer::new(vec![]),
),
Serialize{}.proto_fmt_to_json(&consensus_node.config),
]
}

Expand Down
Loading

0 comments on commit ff3de8c

Please sign in to comment.