From 9797ff88a6ee909db008a7764d1af7b134e537b5 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 16 Oct 2022 20:44:21 -0500 Subject: [PATCH 01/15] Add transparent support --- Cargo.lock | 2 +- consensus/ssz/Cargo.toml | 2 +- consensus/ssz/tests/tests.rs | 43 ++++++++ consensus/ssz_derive/Cargo.toml | 4 +- consensus/ssz_derive/src/lib.rs | 171 +++++++++++++++++++++++++++++--- 5 files changed, 206 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0e3622e77e..4200bc27b0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1829,7 +1829,7 @@ dependencies = [ [[package]] name = "eth2_ssz_derive" -version = "0.3.0" +version = "0.3.1" dependencies = [ "darling", "proc-macro2", diff --git a/consensus/ssz/Cargo.toml b/consensus/ssz/Cargo.toml index a153c2efc14..e521853c218 100644 --- a/consensus/ssz/Cargo.toml +++ b/consensus/ssz/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" name = "ssz" [dev-dependencies] -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" [dependencies] ethereum-types = "0.12.1" diff --git a/consensus/ssz/tests/tests.rs b/consensus/ssz/tests/tests.rs index e41fc15dd4e..475e1b8f678 100644 --- a/consensus/ssz/tests/tests.rs +++ b/consensus/ssz/tests/tests.rs @@ -375,6 +375,7 @@ mod derive_macro { use ssz::{Decode, Encode}; use ssz_derive::{Decode, Encode}; use std::fmt::Debug; + use std::marker::PhantomData; fn assert_encode(item: &T, bytes: &[u8]) { assert_eq!(item.as_ssz_bytes(), bytes); @@ -511,4 +512,46 @@ mod derive_macro { assert_encode_decode(&TwoVecUnion::A(vec![0, 1]), &[0, 0, 1]); assert_encode_decode(&TwoVecUnion::B(vec![0, 1]), &[1, 0, 1]); } + + #[derive(PartialEq, Debug, Encode, Decode)] + #[ssz(transparent)] + struct TransparentStruct { + inner: Vec, + } + + impl TransparentStruct { + fn new(inner: u8) -> Self { + Self { inner: vec![inner] } + } + } + + #[test] + fn transparent_struct() { + assert_encode_decode(&TransparentStruct::new(42), &vec![42_u8].as_ssz_bytes()); + } + + #[derive(PartialEq, Debug, Encode, Decode)] + #[ssz(transparent)] + struct TransparentStructSkippedField { + inner: Vec, + #[ssz(skip_serializing, skip_deserializing)] + skipped: PhantomData, + } + + impl TransparentStructSkippedField { + fn new(inner: u8) -> Self { + Self { + inner: vec![inner], + skipped: PhantomData, + } + } + } + + #[test] + fn transparent_struct_skipped_field() { + assert_encode_decode( + &TransparentStructSkippedField::new(42), + &vec![42_u8].as_ssz_bytes(), + ); + } } diff --git a/consensus/ssz_derive/Cargo.toml b/consensus/ssz_derive/Cargo.toml index cac617d3917..57d65e55738 100644 --- a/consensus/ssz_derive/Cargo.toml +++ b/consensus/ssz_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eth2_ssz_derive" -version = "0.3.0" +version = "0.3.1" authors = ["Paul Hauner "] edition = "2021" description = "Procedural derive macros to accompany the eth2_ssz crate." @@ -15,3 +15,5 @@ syn = "1.0.42" proc-macro2 = "1.0.23" quote = "1.0.7" darling = "0.13.0" + +[dev-dependencies] diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index a5a5a0dddf2..60dea1e9fb3 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -18,6 +18,8 @@ const MAX_UNION_SELECTOR: u8 = 127; struct StructOpts { #[darling(default)] enum_behaviour: Option, + #[darling(default)] + transparent: bool, } /// Field-level configuration. @@ -43,15 +45,20 @@ enum EnumBehaviour { } impl EnumBehaviour { - pub fn new(s: Option) -> Option { - s.map(|s| match s.as_ref() { - ENUM_TRANSPARENT => EnumBehaviour::Transparent, - ENUM_UNION => EnumBehaviour::Union, - other => panic!( - "{} is an invalid enum_behaviour, use either {:?}", - other, ENUM_VARIANTS - ), - }) + pub fn new(s: &StructOpts) -> Option { + s.enum_behaviour + .as_ref() + .map(|behaviour_string| match behaviour_string.as_ref() { + ENUM_TRANSPARENT => EnumBehaviour::Transparent, + ENUM_UNION if s.transparent => { + panic!("cannot use \"transparent\" and \"enum_behaviour(union)\" together") + } + ENUM_UNION => EnumBehaviour::Union, + other => panic!( + "{} is an invalid enum_behaviour, use either {:?}", + other, ENUM_VARIANTS + ), + }) } } @@ -94,14 +101,19 @@ fn parse_ssz_fields(struct_data: &syn::DataStruct) -> Vec<(&syn::Type, &syn::Ide pub fn ssz_encode_derive(input: TokenStream) -> TokenStream { let item = parse_macro_input!(input as DeriveInput); let opts = StructOpts::from_derive_input(&item).unwrap(); - let enum_opt = EnumBehaviour::new(opts.enum_behaviour); + let enum_opt = EnumBehaviour::new(&opts); match &item.data { syn::Data::Struct(s) => { if enum_opt.is_some() { panic!("enum_behaviour is invalid for structs"); } - ssz_encode_derive_struct(&item, s) + + if opts.transparent { + ssz_encode_derive_struct_transparent(&item, s) + } else { + ssz_encode_derive_struct(&item, s) + } } syn::Data::Enum(s) => match enum_opt.expect(NO_ENUM_BEHAVIOUR_ERROR) { EnumBehaviour::Transparent => ssz_encode_derive_enum_transparent(&item, s), @@ -219,6 +231,60 @@ fn ssz_encode_derive_struct(derive_input: &DeriveInput, struct_data: &DataStruct output.into() } +/// Derive `ssz::Encode` "transparently" for a struct which has exactly one non-skipped field. +/// +/// The single field is encoded directly, making the outermost `struct` transparent. +/// +/// ## Field attributes +/// +/// - `#[ssz(skip_serializing)]`: the field will not be serialized. +fn ssz_encode_derive_struct_transparent( + derive_input: &DeriveInput, + struct_data: &DataStruct, +) -> TokenStream { + let name = &derive_input.ident; + let (impl_generics, ty_generics, where_clause) = &derive_input.generics.split_for_impl(); + let ssz_fields = parse_ssz_fields(struct_data); + let num_fields = ssz_fields + .iter() + .filter(|(_, _, field_opts)| !field_opts.skip_deserializing) + .count(); + + if num_fields != 1 { + panic!( + "A \"transparent\" struct must have exactly one non-skipped field ({} fields found)", + num_fields + ); + } + + let (ty, ident, _field_opts) = ssz_fields + .iter() + .filter(|(_, _, field_opts)| !field_opts.skip_deserializing) + .next() + .unwrap(); + + let output = quote! { + impl #impl_generics ssz::Encode for #name #ty_generics #where_clause { + fn is_ssz_fixed_len() -> bool { + <#ty as ssz::Encode>::is_ssz_fixed_len() + } + + fn ssz_fixed_len() -> usize { + <#ty as ssz::Encode>::ssz_fixed_len() + } + + fn ssz_bytes_len(&self) -> usize { + self.#ident.ssz_bytes_len() + } + + fn ssz_append(&self, buf: &mut Vec) { + self.#ident.ssz_append(buf) + } + } + }; + output.into() +} + /// Derive `ssz::Encode` for an enum in the "transparent" method. /// /// The "transparent" method is distinct from the "union" method specified in the SSZ specification. @@ -368,14 +434,18 @@ fn ssz_encode_derive_enum_union(derive_input: &DeriveInput, enum_data: &DataEnum pub fn ssz_decode_derive(input: TokenStream) -> TokenStream { let item = parse_macro_input!(input as DeriveInput); let opts = StructOpts::from_derive_input(&item).unwrap(); - let enum_opt = EnumBehaviour::new(opts.enum_behaviour); + let enum_opt = EnumBehaviour::new(&opts); match &item.data { syn::Data::Struct(s) => { if enum_opt.is_some() { panic!("enum_behaviour is invalid for structs"); } - ssz_decode_derive_struct(&item, s) + if opts.transparent { + ssz_decode_derive_struct_transparent(&item, s) + } else { + ssz_decode_derive_struct(&item, s) + } } syn::Data::Enum(s) => match enum_opt.expect(NO_ENUM_BEHAVIOUR_ERROR) { EnumBehaviour::Transparent => panic!( @@ -545,6 +615,81 @@ fn ssz_decode_derive_struct(item: &DeriveInput, struct_data: &DataStruct) -> Tok output.into() } +/// Implements `ssz::Decode` "transparently" for a `struct` with exactly one non-skipped field. +/// +/// The bytes will be decoded as if they are the inner field, without the outmost struct. The +/// outermost struct will then be applied artificially. +/// +/// ## Field attributes +/// +/// - `#[ssz(skip_deserializing)]`: during de-serialization the field will be instantiated from a +/// `Default` implementation. The decoder will assume that the field was not serialized at all +/// (e.g., if it has been serialized, an error will be raised instead of `Default` overriding it). +fn ssz_decode_derive_struct_transparent( + item: &DeriveInput, + struct_data: &DataStruct, +) -> TokenStream { + let name = &item.ident; + let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl(); + let ssz_fields = parse_ssz_fields(struct_data); + let num_fields = ssz_fields + .iter() + .filter(|(_, _, field_opts)| !field_opts.skip_deserializing) + .count(); + + if num_fields != 1 { + panic!( + "A \"transparent\" struct must have exactly one non-skipped field ({} fields found)", + num_fields + ); + } + + let mut field_names = vec![]; + let mut fields = vec![]; + let mut wrapped_type = None; + + for (ty, ident, field_opts) in ssz_fields { + field_names.push(quote! { + #ident + }); + + if field_opts.skip_deserializing { + fields.push(quote! { + #ident: <_>::default(), + }); + } else { + fields.push(quote! { + #ident: <_>::from_ssz_bytes(bytes)?, + }); + wrapped_type = Some(ty); + } + } + + let ty = wrapped_type.unwrap(); + + let output = quote! { + impl #impl_generics ssz::Decode for #name #ty_generics #where_clause { + fn is_ssz_fixed_len() -> bool { + <#ty as ssz::Decode>::is_ssz_fixed_len() + } + + fn ssz_fixed_len() -> usize { + <#ty as ssz::Decode>::ssz_fixed_len() + } + + fn from_ssz_bytes(bytes: &[u8]) -> std::result::Result { + Ok(Self { + #( + #fields + )* + + }) + } + } + }; + output.into() +} + /// Derive `ssz::Decode` for an `enum` following the "union" SSZ spec. fn ssz_decode_derive_enum_union(derive_input: &DeriveInput, enum_data: &DataEnum) -> TokenStream { let name = &derive_input.ident; From 3c51f6e6fc2f307f1313fa58ce56f8e5d8212ad9 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 17:00:18 +1100 Subject: [PATCH 02/15] Add `Config` struct --- consensus/ssz/tests/tests.rs | 14 ++++ consensus/ssz_derive/src/lib.rs | 119 +++++++++++++++++++------------- 2 files changed, 84 insertions(+), 49 deletions(-) diff --git a/consensus/ssz/tests/tests.rs b/consensus/ssz/tests/tests.rs index 475e1b8f678..72b71fcbf9a 100644 --- a/consensus/ssz/tests/tests.rs +++ b/consensus/ssz/tests/tests.rs @@ -429,6 +429,13 @@ mod derive_macro { B(VariableB), } + #[derive(PartialEq, Debug, Encode)] + #[ssz(transparent)] + enum TwoVariableTransDirectTag { + A(VariableA), + B(VariableB), + } + #[derive(PartialEq, Debug, Encode)] struct TwoVariableTransStruct { a: TwoVariableTrans, @@ -441,6 +448,13 @@ mod derive_macro { B(VariableB), } + #[derive(PartialEq, Debug, Encode, Decode)] + #[ssz(union)] + enum TwoVariableUnionDirectTag { + A(VariableA), + B(VariableB), + } + #[derive(PartialEq, Debug, Encode, Decode)] struct TwoVariableUnionStruct { a: TwoVariableUnion, diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index 60dea1e9fb3..82f15e4cfb5 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -13,6 +13,12 @@ use syn::{parse_macro_input, DataEnum, DataStruct, DeriveInput, Ident}; /// extensions). const MAX_UNION_SELECTOR: u8 = 127; +const ENUM_TRANSPARENT: &str = "transparent"; +const ENUM_UNION: &str = "union"; +const ENUM_VARIANTS: &[&str] = &[ENUM_TRANSPARENT, ENUM_UNION]; +const NO_ENUM_BEHAVIOUR_ERROR: &str = "enums require a \"transparent\" or \"union\" attribute, \ + e.g., #[ssz(transparent)]"; + #[derive(Debug, FromDeriveInput)] #[darling(attributes(ssz))] struct StructOpts { @@ -20,6 +26,8 @@ struct StructOpts { enum_behaviour: Option, #[darling(default)] transparent: bool, + #[darling(default)] + union: bool, } /// Field-level configuration. @@ -33,35 +41,62 @@ struct FieldOpts { skip_deserializing: bool, } -const ENUM_TRANSPARENT: &str = "transparent"; -const ENUM_UNION: &str = "union"; -const ENUM_VARIANTS: &[&str] = &[ENUM_TRANSPARENT, ENUM_UNION]; -const NO_ENUM_BEHAVIOUR_ERROR: &str = "enums require an \"enum_behaviour\" attribute, \ - e.g., #[ssz(enum_behaviour = \"transparent\")]"; - -enum EnumBehaviour { - Transparent, - Union, +struct Config { + struct_behaviour: StructBehaviour, + enum_behaviour: EnumBehaviour, } -impl EnumBehaviour { - pub fn new(s: &StructOpts) -> Option { - s.enum_behaviour - .as_ref() - .map(|behaviour_string| match behaviour_string.as_ref() { +impl Config { + fn read(item: &DeriveInput) -> Self { + let opts = StructOpts::from_derive_input(item).unwrap(); + + let enum_behaviour = match (opts.transparent, opts.union, &opts.enum_behaviour) { + (false, false, None) => EnumBehaviour::Unspecified, + (true, false, None) => EnumBehaviour::Transparent, + (false, true, None) => EnumBehaviour::Union, + (false, false, Some(behaviour_string)) => match behaviour_string.as_ref() { ENUM_TRANSPARENT => EnumBehaviour::Transparent, - ENUM_UNION if s.transparent => { - panic!("cannot use \"transparent\" and \"enum_behaviour(union)\" together") - } ENUM_UNION => EnumBehaviour::Union, other => panic!( "{} is an invalid enum_behaviour, use either {:?}", other, ENUM_VARIANTS ), - }) + }, + (true, true, _) => panic!("cannot provide both \"transparent\" and \"union\""), + (_, _, Some(_)) => { + panic!("\"enum_behaviour\" cannot be used with \"transparent\" or \"union\"") + } + }; + + // Don't allow `enum_behaviour` for structs. + if matches!(item.data, syn::Data::Struct(_)) && opts.enum_behaviour.is_some() { + panic!("cannot provide \"enum_behaviour\" for a struct") + } + + let struct_behaviour = if opts.transparent { + StructBehaviour::Transparent + } else { + StructBehaviour::Container + }; + + Self { + struct_behaviour, + enum_behaviour, + } } } +enum StructBehaviour { + Transparent, + Container, +} + +enum EnumBehaviour { + Transparent, + Union, + Unspecified, +} + fn parse_ssz_fields(struct_data: &syn::DataStruct) -> Vec<(&syn::Type, &syn::Ident, FieldOpts)> { struct_data .fields @@ -100,24 +135,17 @@ fn parse_ssz_fields(struct_data: &syn::DataStruct) -> Vec<(&syn::Type, &syn::Ide #[proc_macro_derive(Encode, attributes(ssz))] pub fn ssz_encode_derive(input: TokenStream) -> TokenStream { let item = parse_macro_input!(input as DeriveInput); - let opts = StructOpts::from_derive_input(&item).unwrap(); - let enum_opt = EnumBehaviour::new(&opts); + let config = Config::read(&item); match &item.data { - syn::Data::Struct(s) => { - if enum_opt.is_some() { - panic!("enum_behaviour is invalid for structs"); - } - - if opts.transparent { - ssz_encode_derive_struct_transparent(&item, s) - } else { - ssz_encode_derive_struct(&item, s) - } - } - syn::Data::Enum(s) => match enum_opt.expect(NO_ENUM_BEHAVIOUR_ERROR) { + syn::Data::Struct(s) => match config.struct_behaviour { + StructBehaviour::Transparent => ssz_encode_derive_struct_transparent(&item, s), + StructBehaviour::Container => ssz_encode_derive_struct(&item, s), + }, + syn::Data::Enum(s) => match config.enum_behaviour { EnumBehaviour::Transparent => ssz_encode_derive_enum_transparent(&item, s), EnumBehaviour::Union => ssz_encode_derive_enum_union(&item, s), + EnumBehaviour::Unspecified => panic!("{}", NO_ENUM_BEHAVIOUR_ERROR), }, _ => panic!("ssz_derive only supports structs and enums"), } @@ -259,9 +287,8 @@ fn ssz_encode_derive_struct_transparent( let (ty, ident, _field_opts) = ssz_fields .iter() - .filter(|(_, _, field_opts)| !field_opts.skip_deserializing) - .next() - .unwrap(); + .find(|(_, _, field_opts)| !field_opts.skip_deserializing) + .expect("\"transparent\" struct must have at least one non-skipped field"); let output = quote! { impl #impl_generics ssz::Encode for #name #ty_generics #where_clause { @@ -433,26 +460,20 @@ fn ssz_encode_derive_enum_union(derive_input: &DeriveInput, enum_data: &DataEnum #[proc_macro_derive(Decode, attributes(ssz))] pub fn ssz_decode_derive(input: TokenStream) -> TokenStream { let item = parse_macro_input!(input as DeriveInput); - let opts = StructOpts::from_derive_input(&item).unwrap(); - let enum_opt = EnumBehaviour::new(&opts); + let config = Config::read(&item); match &item.data { - syn::Data::Struct(s) => { - if enum_opt.is_some() { - panic!("enum_behaviour is invalid for structs"); - } - if opts.transparent { - ssz_decode_derive_struct_transparent(&item, s) - } else { - ssz_decode_derive_struct(&item, s) - } - } - syn::Data::Enum(s) => match enum_opt.expect(NO_ENUM_BEHAVIOUR_ERROR) { + syn::Data::Struct(s) => match config.struct_behaviour { + StructBehaviour::Transparent => ssz_decode_derive_struct_transparent(&item, s), + StructBehaviour::Container => ssz_decode_derive_struct(&item, s), + }, + syn::Data::Enum(s) => match config.enum_behaviour { + EnumBehaviour::Union => ssz_decode_derive_enum_union(&item, s), EnumBehaviour::Transparent => panic!( "Decode cannot be derived for enum_behaviour \"{}\", only \"{}\" is valid.", ENUM_TRANSPARENT, ENUM_UNION ), - EnumBehaviour::Union => ssz_decode_derive_enum_union(&item, s), + EnumBehaviour::Unspecified => panic!("{}", NO_ENUM_BEHAVIOUR_ERROR), }, _ => panic!("ssz_derive only supports structs and enums"), } From 89b64a6f53d0f68685be88d5b60d39799d9933b5 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 17:48:15 +1100 Subject: [PATCH 03/15] Deprecate `enum_behaviour` --- Cargo.lock | 45 ++++++---- consensus/ssz/Cargo.toml | 2 +- consensus/ssz/tests/tests.rs | 22 +---- consensus/ssz_derive/Cargo.toml | 3 +- consensus/ssz_derive/src/lib.rs | 145 ++++++++++++++++++++++++++++---- 5 files changed, 163 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4200bc27b0d..2be8b1a0641 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,7 +393,7 @@ dependencies = [ "eth2", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "execution_layer", "exit-future", @@ -714,7 +714,7 @@ version = "0.1.0" dependencies = [ "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "ethereum-types 0.12.1", "quickcheck", @@ -1498,7 +1498,7 @@ dependencies = [ "compare_fields_derive", "derivative", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "ethereum-types 0.12.1", "fork_choice", "fs2", @@ -1661,7 +1661,7 @@ dependencies = [ "eth1_test_rig", "eth2", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "execution_layer", "futures", "hex", @@ -1705,7 +1705,7 @@ dependencies = [ "eth2_keystore", "eth2_serde_utils", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "futures", "futures-util", "libsecp256k1", @@ -1821,7 +1821,7 @@ dependencies = [ name = "eth2_ssz" version = "0.4.1" dependencies = [ - "eth2_ssz_derive", + "eth2_ssz_derive 0.4.0", "ethereum-types 0.12.1", "itertools", "smallvec", @@ -1829,9 +1829,22 @@ dependencies = [ [[package]] name = "eth2_ssz_derive" -version = "0.3.1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "635b86d2c941bb71e7419a571e1763d65c93e51a1bafc400352e3bef6ff59fc9" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "eth2_ssz_derive" +version = "0.4.0" dependencies = [ "darling", + "eth2_ssz", "proc-macro2", "quote", "syn", @@ -2240,7 +2253,7 @@ version = "0.1.0" dependencies = [ "beacon_chain", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "proto_array", "slog", "state_processing", @@ -3660,7 +3673,7 @@ dependencies = [ "discv5", "error-chain", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "exit-future", "fnv", @@ -4420,7 +4433,7 @@ dependencies = [ "bitvec 1.0.1", "derivative", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "itertools", "lazy_static", "lighthouse_metrics", @@ -5007,7 +5020,7 @@ name = "proto_array" version = "0.2.0" dependencies = [ "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "serde", "serde_derive", "serde_yaml", @@ -5980,7 +5993,7 @@ dependencies = [ "bincode", "byteorder", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "filesystem", "flate2", "lazy_static", @@ -6267,7 +6280,7 @@ dependencies = [ "env_logger 0.9.0", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "int_to_bytes", "integer-sqrt", @@ -6309,7 +6322,7 @@ dependencies = [ "db-key", "directory", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "itertools", "lazy_static", "leveldb", @@ -6946,7 +6959,7 @@ dependencies = [ "beacon_chain", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "ethereum-types 0.12.1", "rand 0.8.5", "smallvec", @@ -7085,7 +7098,7 @@ dependencies = [ "eth2_interop_keypairs", "eth2_serde_utils", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "ethereum-types 0.12.1", "hex", diff --git a/consensus/ssz/Cargo.toml b/consensus/ssz/Cargo.toml index e521853c218..633ffc8e941 100644 --- a/consensus/ssz/Cargo.toml +++ b/consensus/ssz/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" name = "ssz" [dev-dependencies] -eth2_ssz_derive = "0.3.1" +eth2_ssz_derive = "0.4.0" [dependencies] ethereum-types = "0.12.1" diff --git a/consensus/ssz/tests/tests.rs b/consensus/ssz/tests/tests.rs index 72b71fcbf9a..1b61b8510a7 100644 --- a/consensus/ssz/tests/tests.rs +++ b/consensus/ssz/tests/tests.rs @@ -387,7 +387,7 @@ mod derive_macro { } #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(enum_behaviour = "union")] + #[ssz(union)] enum TwoFixedUnion { U8(u8), U16(u16), @@ -422,16 +422,9 @@ mod derive_macro { b: u8, } - #[derive(PartialEq, Debug, Encode)] - #[ssz(enum_behaviour = "transparent")] - enum TwoVariableTrans { - A(VariableA), - B(VariableB), - } - #[derive(PartialEq, Debug, Encode)] #[ssz(transparent)] - enum TwoVariableTransDirectTag { + enum TwoVariableTrans { A(VariableA), B(VariableB), } @@ -441,16 +434,9 @@ mod derive_macro { a: TwoVariableTrans, } - #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(enum_behaviour = "union")] - enum TwoVariableUnion { - A(VariableA), - B(VariableB), - } - #[derive(PartialEq, Debug, Encode, Decode)] #[ssz(union)] - enum TwoVariableUnionDirectTag { + enum TwoVariableUnion { A(VariableA), B(VariableB), } @@ -509,7 +495,7 @@ mod derive_macro { } #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(enum_behaviour = "union")] + #[ssz(union)] enum TwoVecUnion { A(Vec), B(Vec), diff --git a/consensus/ssz_derive/Cargo.toml b/consensus/ssz_derive/Cargo.toml index 57d65e55738..2f656a9bf24 100644 --- a/consensus/ssz_derive/Cargo.toml +++ b/consensus/ssz_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eth2_ssz_derive" -version = "0.3.1" +version = "0.4.0" authors = ["Paul Hauner "] edition = "2021" description = "Procedural derive macros to accompany the eth2_ssz crate." @@ -17,3 +17,4 @@ quote = "1.0.7" darling = "0.13.0" [dev-dependencies] +eth2_ssz = "0.4.1" diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index 82f15e4cfb5..cf97acb5029 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -1,7 +1,127 @@ #![recursion_limit = "256"] //! Provides procedural derive macros for the `Encode` and `Decode` traits of the `eth2_ssz` crate. //! -//! Supports field attributes, see each derive macro for more information. +//! ## Struct Attributes +//! +//! The following struct attributes are available: +//! +//! - `#[ssz(union)]` +//! - For `enum`, implements `ssz::Encode` and `ssz::Decode` such that the union variant is +//! encoded as a single byte in the SSZ vector. +//! - Not supported for `struct`. +//! - `#[ssz(transparent)]` +//! - For `enum`, implements `ssz::Encode` such that the `enum` is ignored. `ssz::Decode` is not +//! supported. +//! - For `struct`, implements `ssz::Encode` and `ssz::Decode` such that the outermost `struct` +//! is ignored for encoding and decoding. This is useful for new-type wrappers. The `struct` +//! must have exactly one non-skipped field. +//! +//! ## Field Attributes +//! +//! The following field attributes are available: +//! +//! - `#[ssz(with = "module")]`: uses the methods in `module` to implement `ssz::Encode` or +//! `ssz::Decode`. This is useful when it's not possible to create an `impl` for that type +//! (perhaps it is defined in another crate). +//! - `#[ssz(skip_serializing)]`: this field will not be included in the serialized SSZ vector. +//! - `#[ssz(skip_deserializing)]`: this field will not be expected to be included in the serialized +//! SSZ vector and it will be initialized from a `Default` implementation. +//! +//! ## Examples +//! +//! ### Structs +//! +//! ```rust +//! use ssz::{Encode, Decode}; +//! use ssz_derive::{Encode, Decode}; +//! +//! /// Represented as an SSZ "list" wrapped in an SSZ "container". +//! #[derive(Debug, PartialEq, Encode, Decode)] +//! struct TypicalStruct { +//! foo: Vec +//! } +//! +//! assert_eq!( +//! TypicalStruct { foo: vec![42] }.as_ssz_bytes(), +//! vec![4, 0, 0, 0, 42] +//! ); +//! +//! assert_eq!( +//! TypicalStruct::from_ssz_bytes(&[4, 0, 0, 0, 42]).unwrap(), +//! TypicalStruct { foo: vec![42] }, +//! ); +//! +//! /// Represented as an SSZ "list" *without* an SSZ "container". +//! #[derive(Encode, Decode)] +//! #[ssz(transparent)] +//! struct NewType { +//! foo: Vec +//! } +//! +//! assert_eq!( +//! NewType { foo: vec![42] }.as_ssz_bytes(), +//! vec![42] +//! ); +//! +//! /// Represented as an SSZ "list" *without* an SSZ "container". The `bar` byte is ignored. +//! #[derive(Debug, PartialEq, Encode, Decode)] +//! #[ssz(transparent)] +//! struct NewTypeSkippedField { +//! foo: Vec, +//! #[ssz(skip_serializing, skip_deserializing)] +//! bar: u8, +//! } +//! +//! assert_eq!( +//! NewTypeSkippedField { foo: vec![42], bar: 99 }.as_ssz_bytes(), +//! vec![42] +//! ); +//! assert_eq!( +//! NewTypeSkippedField::from_ssz_bytes(&[42]).unwrap(), +//! NewTypeSkippedField { foo: vec![42], bar: 0 } +//! ); +//! ``` +//! +//! ### Enums +//! +//! ```rust +//! use ssz::{Encode, Decode}; +//! use ssz_derive::{Encode, Decode}; +//! +//! /// Represented as an SSZ "union". +//! #[derive(Debug, PartialEq, Encode, Decode)] +//! #[ssz(union)] +//! enum UnionEnum { +//! Foo(u8), +//! Bar(u8), +//! } +//! +//! assert_eq!( +//! UnionEnum::Foo(42).as_ssz_bytes(), +//! vec![0, 42] +//! ); +//! assert_eq!( +//! UnionEnum::from_ssz_bytes(&[1, 42]).unwrap(), +//! UnionEnum::Bar(42), +//! ); +//! +//! /// Represented as only the value in the enum variant. +//! #[derive(Debug, PartialEq, Encode)] +//! #[ssz(transparent)] +//! enum TransparentEnum { +//! Foo(u8), +//! Bar(Vec), +//! } +//! +//! assert_eq!( +//! TransparentEnum::Foo(42).as_ssz_bytes(), +//! vec![42] +//! ); +//! assert_eq!( +//! TransparentEnum::Bar(vec![42, 42]).as_ssz_bytes(), +//! vec![42, 42] +//! ); +//! ``` use darling::{FromDeriveInput, FromMeta}; use proc_macro::TokenStream; @@ -13,11 +133,8 @@ use syn::{parse_macro_input, DataEnum, DataStruct, DeriveInput, Ident}; /// extensions). const MAX_UNION_SELECTOR: u8 = 127; -const ENUM_TRANSPARENT: &str = "transparent"; -const ENUM_UNION: &str = "union"; -const ENUM_VARIANTS: &[&str] = &[ENUM_TRANSPARENT, ENUM_UNION]; const NO_ENUM_BEHAVIOUR_ERROR: &str = "enums require a \"transparent\" or \"union\" attribute, \ - e.g., #[ssz(transparent)]"; + e.g., #[ssz(transparent)] or #[ssz(union)]"; #[derive(Debug, FromDeriveInput)] #[darling(attributes(ssz))] @@ -54,18 +171,11 @@ impl Config { (false, false, None) => EnumBehaviour::Unspecified, (true, false, None) => EnumBehaviour::Transparent, (false, true, None) => EnumBehaviour::Union, - (false, false, Some(behaviour_string)) => match behaviour_string.as_ref() { - ENUM_TRANSPARENT => EnumBehaviour::Transparent, - ENUM_UNION => EnumBehaviour::Union, - other => panic!( - "{} is an invalid enum_behaviour, use either {:?}", - other, ENUM_VARIANTS - ), - }, (true, true, _) => panic!("cannot provide both \"transparent\" and \"union\""), - (_, _, Some(_)) => { - panic!("\"enum_behaviour\" cannot be used with \"transparent\" or \"union\"") - } + (_, _, Some(_)) => panic!( + "the \"enum_behaviour\" attribute has been removed, please use \ + either #[ssz(transparent)] or #[ssz(union)] instead" + ), }; // Don't allow `enum_behaviour` for structs. @@ -470,8 +580,7 @@ pub fn ssz_decode_derive(input: TokenStream) -> TokenStream { syn::Data::Enum(s) => match config.enum_behaviour { EnumBehaviour::Union => ssz_decode_derive_enum_union(&item, s), EnumBehaviour::Transparent => panic!( - "Decode cannot be derived for enum_behaviour \"{}\", only \"{}\" is valid.", - ENUM_TRANSPARENT, ENUM_UNION + "Decode cannot be derived for enum_behaviour \"transparent\", only \"union\" is valid." ), EnumBehaviour::Unspecified => panic!("{}", NO_ENUM_BEHAVIOUR_ERROR), }, From 46ffb7fe77622cf420f7ba2fccf432c0050535d6 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 18:09:57 +1100 Subject: [PATCH 04/15] Partially remove enum_behaviour from project --- Cargo.lock | 42 +++++++------------ beacon_node/beacon_chain/Cargo.toml | 2 +- beacon_node/eth1/Cargo.toml | 2 +- beacon_node/lighthouse_network/Cargo.toml | 2 +- .../lighthouse_network/src/rpc/methods.rs | 2 +- beacon_node/operation_pool/Cargo.toml | 2 +- beacon_node/store/Cargo.toml | 2 +- beacon_node/store/src/partial_beacon_state.rs | 2 +- common/eth2/Cargo.toml | 2 +- consensus/cached_tree_hash/Cargo.toml | 2 +- consensus/fork_choice/Cargo.toml | 2 +- consensus/proto_array/Cargo.toml | 2 +- .../src/proto_array_fork_choice.rs | 2 +- consensus/ssz_derive/src/lib.rs | 17 ++++---- consensus/state_processing/Cargo.toml | 2 +- consensus/tree_hash/Cargo.toml | 2 +- consensus/types/Cargo.toml | 2 +- consensus/types/src/beacon_block.rs | 2 +- consensus/types/src/beacon_state.rs | 2 +- consensus/types/src/signed_beacon_block.rs | 2 +- slasher/Cargo.toml | 2 +- testing/ef_tests/Cargo.toml | 2 +- 22 files changed, 45 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2be8b1a0641..a0e0cb0f2a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,7 +393,7 @@ dependencies = [ "eth2", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "execution_layer", "exit-future", @@ -714,7 +714,7 @@ version = "0.1.0" dependencies = [ "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "ethereum-types 0.12.1", "quickcheck", @@ -1498,7 +1498,7 @@ dependencies = [ "compare_fields_derive", "derivative", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "ethereum-types 0.12.1", "fork_choice", "fs2", @@ -1661,7 +1661,7 @@ dependencies = [ "eth1_test_rig", "eth2", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "execution_layer", "futures", "hex", @@ -1705,7 +1705,7 @@ dependencies = [ "eth2_keystore", "eth2_serde_utils", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "futures", "futures-util", "libsecp256k1", @@ -1821,24 +1821,12 @@ dependencies = [ name = "eth2_ssz" version = "0.4.1" dependencies = [ - "eth2_ssz_derive 0.4.0", + "eth2_ssz_derive", "ethereum-types 0.12.1", "itertools", "smallvec", ] -[[package]] -name = "eth2_ssz_derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "635b86d2c941bb71e7419a571e1763d65c93e51a1bafc400352e3bef6ff59fc9" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "eth2_ssz_derive" version = "0.4.0" @@ -2253,7 +2241,7 @@ version = "0.1.0" dependencies = [ "beacon_chain", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "proto_array", "slog", "state_processing", @@ -3673,7 +3661,7 @@ dependencies = [ "discv5", "error-chain", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "exit-future", "fnv", @@ -4433,7 +4421,7 @@ dependencies = [ "bitvec 1.0.1", "derivative", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "itertools", "lazy_static", "lighthouse_metrics", @@ -5020,7 +5008,7 @@ name = "proto_array" version = "0.2.0" dependencies = [ "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "serde", "serde_derive", "serde_yaml", @@ -5993,7 +5981,7 @@ dependencies = [ "bincode", "byteorder", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "filesystem", "flate2", "lazy_static", @@ -6280,7 +6268,7 @@ dependencies = [ "env_logger 0.9.0", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "int_to_bytes", "integer-sqrt", @@ -6322,7 +6310,7 @@ dependencies = [ "db-key", "directory", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "itertools", "lazy_static", "leveldb", @@ -6959,7 +6947,7 @@ dependencies = [ "beacon_chain", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "ethereum-types 0.12.1", "rand 0.8.5", "smallvec", @@ -7098,7 +7086,7 @@ dependencies = [ "eth2_interop_keypairs", "eth2_serde_utils", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "ethereum-types 0.12.1", "hex", diff --git a/beacon_node/beacon_chain/Cargo.toml b/beacon_node/beacon_chain/Cargo.toml index dd185ac7571..0939576c470 100644 --- a/beacon_node/beacon_chain/Cargo.toml +++ b/beacon_node/beacon_chain/Cargo.toml @@ -33,7 +33,7 @@ slot_clock = { path = "../../common/slot_clock" } eth2_hashing = "0.3.0" eth2_ssz = "0.4.1" eth2_ssz_types = "0.2.2" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" state_processing = { path = "../../consensus/state_processing" } tree_hash = "0.4.1" types = { path = "../../consensus/types" } diff --git a/beacon_node/eth1/Cargo.toml b/beacon_node/eth1/Cargo.toml index 930301256c6..2ee8ac6cdbc 100644 --- a/beacon_node/eth1/Cargo.toml +++ b/beacon_node/eth1/Cargo.toml @@ -21,7 +21,7 @@ hex = "0.4.2" types = { path = "../../consensus/types"} merkle_proof = { path = "../../consensus/merkle_proof"} eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" tree_hash = "0.4.1" parking_lot = "0.12.0" slog = "2.5.2" diff --git a/beacon_node/lighthouse_network/Cargo.toml b/beacon_node/lighthouse_network/Cargo.toml index e5af0a74999..f7745ea4097 100644 --- a/beacon_node/lighthouse_network/Cargo.toml +++ b/beacon_node/lighthouse_network/Cargo.toml @@ -12,7 +12,7 @@ eth2_ssz_types = "0.2.2" serde = { version = "1.0.116", features = ["derive"] } serde_derive = "1.0.116" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" slog = { version = "2.5.2", features = ["max_level_trace"] } lighthouse_version = { path = "../../common/lighthouse_version" } tokio = { version = "1.14.0", features = ["time", "macros"] } diff --git a/beacon_node/lighthouse_network/src/rpc/methods.rs b/beacon_node/lighthouse_network/src/rpc/methods.rs index 26d755a6e06..46f69dfc166 100644 --- a/beacon_node/lighthouse_network/src/rpc/methods.rs +++ b/beacon_node/lighthouse_network/src/rpc/methods.rs @@ -93,7 +93,7 @@ pub struct Ping { )] #[derive(Clone, Debug, PartialEq, Serialize, Encode)] #[serde(bound = "T: EthSpec")] -#[ssz(enum_behaviour = "transparent")] +#[ssz(transparent)] pub struct MetaData { /// A sequential counter indicating when data gets modified. pub seq_number: u64, diff --git a/beacon_node/operation_pool/Cargo.toml b/beacon_node/operation_pool/Cargo.toml index 1d67ecdccc2..997589e13bc 100644 --- a/beacon_node/operation_pool/Cargo.toml +++ b/beacon_node/operation_pool/Cargo.toml @@ -13,7 +13,7 @@ parking_lot = "0.12.0" types = { path = "../../consensus/types" } state_processing = { path = "../../consensus/state_processing" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" rayon = "1.5.0" serde = "1.0.116" serde_derive = "1.0.116" diff --git a/beacon_node/store/Cargo.toml b/beacon_node/store/Cargo.toml index 20ae37b3b14..5c3675b2090 100644 --- a/beacon_node/store/Cargo.toml +++ b/beacon_node/store/Cargo.toml @@ -14,7 +14,7 @@ leveldb = { version = "0.8.6", default-features = false } parking_lot = "0.12.0" itertools = "0.10.0" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" types = { path = "../../consensus/types" } state_processing = { path = "../../consensus/state_processing" } slog = "2.5.2" diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index 010796afd5b..decd396cc55 100644 --- a/beacon_node/store/src/partial_beacon_state.rs +++ b/beacon_node/store/src/partial_beacon_state.rs @@ -18,7 +18,7 @@ use types::*; variant_attributes(derive(Debug, PartialEq, Clone, Encode, Decode)) )] #[derive(Debug, PartialEq, Clone, Encode)] -#[ssz(enum_behaviour = "transparent")] +#[ssz(transparent)] pub struct PartialBeaconState where T: EthSpec, diff --git a/common/eth2/Cargo.toml b/common/eth2/Cargo.toml index 294f8ec8a3d..74b44eab5f0 100644 --- a/common/eth2/Cargo.toml +++ b/common/eth2/Cargo.toml @@ -21,7 +21,7 @@ bytes = "1.0.1" account_utils = { path = "../../common/account_utils" } sensitive_url = { path = "../../common/sensitive_url" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" futures-util = "0.3.8" futures = "0.3.8" store = { path = "../../beacon_node/store", optional = true } diff --git a/consensus/cached_tree_hash/Cargo.toml b/consensus/cached_tree_hash/Cargo.toml index f9433e4a496..f8e63fd44dd 100644 --- a/consensus/cached_tree_hash/Cargo.toml +++ b/consensus/cached_tree_hash/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" ethereum-types = "0.12.1" eth2_ssz_types = "0.2.2" eth2_hashing = "0.3.0" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" eth2_ssz = "0.4.1" tree_hash = "0.4.1" smallvec = "1.6.1" diff --git a/consensus/fork_choice/Cargo.toml b/consensus/fork_choice/Cargo.toml index 52a738351ef..ddc9ab47076 100644 --- a/consensus/fork_choice/Cargo.toml +++ b/consensus/fork_choice/Cargo.toml @@ -11,7 +11,7 @@ types = { path = "../types" } state_processing = { path = "../state_processing" } proto_array = { path = "../proto_array" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" slog = { version = "2.5.2", features = ["max_level_trace", "release_max_level_trace"] } [dev-dependencies] diff --git a/consensus/proto_array/Cargo.toml b/consensus/proto_array/Cargo.toml index ad79ecc1e6b..e72279432fa 100644 --- a/consensus/proto_array/Cargo.toml +++ b/consensus/proto_array/Cargo.toml @@ -11,7 +11,7 @@ path = "src/bin.rs" [dependencies] types = { path = "../types" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" serde = "1.0.116" serde_derive = "1.0.116" serde_yaml = "0.8.13" diff --git a/consensus/proto_array/src/proto_array_fork_choice.rs b/consensus/proto_array/src/proto_array_fork_choice.rs index 8f5d062ec6a..0ebc286fc5a 100644 --- a/consensus/proto_array/src/proto_array_fork_choice.rs +++ b/consensus/proto_array/src/proto_array_fork_choice.rs @@ -24,7 +24,7 @@ pub struct VoteTracker { /// Represents the verification status of an execution payload. #[derive(Clone, Copy, Debug, PartialEq, Encode, Decode, Serialize, Deserialize)] -#[ssz(enum_behaviour = "union")] +#[ssz(union)] pub enum ExecutionStatus { /// An EL has determined that the payload is valid. Valid(ExecutionBlockHash), diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index cf97acb5029..b62996fc5f6 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -167,15 +167,18 @@ impl Config { fn read(item: &DeriveInput) -> Self { let opts = StructOpts::from_derive_input(item).unwrap(); - let enum_behaviour = match (opts.transparent, opts.union, &opts.enum_behaviour) { - (false, false, None) => EnumBehaviour::Unspecified, - (true, false, None) => EnumBehaviour::Transparent, - (false, true, None) => EnumBehaviour::Union, - (true, true, _) => panic!("cannot provide both \"transparent\" and \"union\""), - (_, _, Some(_)) => panic!( + if opts.enum_behaviour.is_some() { + panic!( "the \"enum_behaviour\" attribute has been removed, please use \ either #[ssz(transparent)] or #[ssz(union)] instead" - ), + ) + } + + let enum_behaviour = match (opts.transparent, opts.union) { + (true, true) => panic!("cannot provide both \"transparent\" and \"union\""), + (false, false) => EnumBehaviour::Unspecified, + (true, false) => EnumBehaviour::Transparent, + (false, true) => EnumBehaviour::Union, }; // Don't allow `enum_behaviour` for structs. diff --git a/consensus/state_processing/Cargo.toml b/consensus/state_processing/Cargo.toml index 46ac2bae577..f9710f7cc85 100644 --- a/consensus/state_processing/Cargo.toml +++ b/consensus/state_processing/Cargo.toml @@ -14,7 +14,7 @@ bls = { path = "../../crypto/bls" } integer-sqrt = "0.1.5" itertools = "0.10.0" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" eth2_ssz_types = "0.2.2" merkle_proof = { path = "../merkle_proof" } safe_arith = { path = "../safe_arith" } diff --git a/consensus/tree_hash/Cargo.toml b/consensus/tree_hash/Cargo.toml index ab080eac065..26724a7b771 100644 --- a/consensus/tree_hash/Cargo.toml +++ b/consensus/tree_hash/Cargo.toml @@ -12,7 +12,7 @@ tree_hash_derive = "0.4.0" types = { path = "../types" } beacon_chain = { path = "../../beacon_node/beacon_chain" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" [dependencies] ethereum-types = "0.12.1" diff --git a/consensus/types/Cargo.toml b/consensus/types/Cargo.toml index 68fdbf7990d..81d70561e3c 100644 --- a/consensus/types/Cargo.toml +++ b/consensus/types/Cargo.toml @@ -25,7 +25,7 @@ serde = {version = "1.0.116" , features = ["rc"] } serde_derive = "1.0.116" slog = "2.5.2" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" eth2_ssz_types = "0.2.2" swap_or_not_shuffle = { path = "../swap_or_not_shuffle" } test_random_derive = { path = "../../common/test_random_derive" } diff --git a/consensus/types/src/beacon_block.rs b/consensus/types/src/beacon_block.rs index 0ec1f9a3741..52853381b08 100644 --- a/consensus/types/src/beacon_block.rs +++ b/consensus/types/src/beacon_block.rs @@ -47,7 +47,7 @@ use tree_hash_derive::TreeHash; #[serde(bound = "T: EthSpec, Payload: ExecPayload")] #[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))] #[tree_hash(enum_behaviour = "transparent")] -#[ssz(enum_behaviour = "transparent")] +#[ssz(transparent)] pub struct BeaconBlock = FullPayload> { #[superstruct(getter(copy))] pub slot: Slot, diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index a5d00cdf2dd..b11fc192c06 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -198,7 +198,7 @@ impl From for Hash256 { #[serde(bound = "T: EthSpec")] #[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))] #[tree_hash(enum_behaviour = "transparent")] -#[ssz(enum_behaviour = "transparent")] +#[ssz(transparent)] pub struct BeaconState where T: EthSpec, diff --git a/consensus/types/src/signed_beacon_block.rs b/consensus/types/src/signed_beacon_block.rs index 5c40c4685c3..fdb5047cc89 100644 --- a/consensus/types/src/signed_beacon_block.rs +++ b/consensus/types/src/signed_beacon_block.rs @@ -64,7 +64,7 @@ impl From for Hash256 { #[serde(bound = "E: EthSpec, Payload: ExecPayload")] #[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))] #[tree_hash(enum_behaviour = "transparent")] -#[ssz(enum_behaviour = "transparent")] +#[ssz(transparent)] pub struct SignedBeaconBlock = FullPayload> { #[superstruct(only(Base), partial_getter(rename = "message_base"))] pub message: BeaconBlockBase, diff --git a/slasher/Cargo.toml b/slasher/Cargo.toml index 0f24fe9f04f..406a604f2a2 100644 --- a/slasher/Cargo.toml +++ b/slasher/Cargo.toml @@ -13,7 +13,7 @@ lmdb = ["lmdb-rkv", "lmdb-rkv-sys"] bincode = "1.3.1" byteorder = "1.3.4" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" flate2 = { version = "1.0.14", features = ["zlib"], default-features = false } lazy_static = "1.4.0" lighthouse_metrics = { path = "../common/lighthouse_metrics" } diff --git a/testing/ef_tests/Cargo.toml b/testing/ef_tests/Cargo.toml index e04d671396e..73f0a7ca412 100644 --- a/testing/ef_tests/Cargo.toml +++ b/testing/ef_tests/Cargo.toml @@ -23,7 +23,7 @@ serde_derive = "1.0.116" serde_repr = "0.1.6" serde_yaml = "0.8.13" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.4.0" tree_hash = "0.4.1" tree_hash_derive = "0.4.0" cached_tree_hash = { path = "../../consensus/cached_tree_hash" } From 1fa57a0760a7bf9e9a1cbb0a4816386100724a3b Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 18:10:31 +1100 Subject: [PATCH 05/15] Revert "Partially remove enum_behaviour from project" This reverts commit 46ffb7fe77622cf420f7ba2fccf432c0050535d6. --- Cargo.lock | 42 ++++++++++++------- beacon_node/beacon_chain/Cargo.toml | 2 +- beacon_node/eth1/Cargo.toml | 2 +- beacon_node/lighthouse_network/Cargo.toml | 2 +- .../lighthouse_network/src/rpc/methods.rs | 2 +- beacon_node/operation_pool/Cargo.toml | 2 +- beacon_node/store/Cargo.toml | 2 +- beacon_node/store/src/partial_beacon_state.rs | 2 +- common/eth2/Cargo.toml | 2 +- consensus/cached_tree_hash/Cargo.toml | 2 +- consensus/fork_choice/Cargo.toml | 2 +- consensus/proto_array/Cargo.toml | 2 +- .../src/proto_array_fork_choice.rs | 2 +- consensus/ssz_derive/src/lib.rs | 17 ++++---- consensus/state_processing/Cargo.toml | 2 +- consensus/tree_hash/Cargo.toml | 2 +- consensus/types/Cargo.toml | 2 +- consensus/types/src/beacon_block.rs | 2 +- consensus/types/src/beacon_state.rs | 2 +- consensus/types/src/signed_beacon_block.rs | 2 +- slasher/Cargo.toml | 2 +- testing/ef_tests/Cargo.toml | 2 +- 22 files changed, 54 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0e0cb0f2a3..2be8b1a0641 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,7 +393,7 @@ dependencies = [ "eth2", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "execution_layer", "exit-future", @@ -714,7 +714,7 @@ version = "0.1.0" dependencies = [ "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "ethereum-types 0.12.1", "quickcheck", @@ -1498,7 +1498,7 @@ dependencies = [ "compare_fields_derive", "derivative", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "ethereum-types 0.12.1", "fork_choice", "fs2", @@ -1661,7 +1661,7 @@ dependencies = [ "eth1_test_rig", "eth2", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "execution_layer", "futures", "hex", @@ -1705,7 +1705,7 @@ dependencies = [ "eth2_keystore", "eth2_serde_utils", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "futures", "futures-util", "libsecp256k1", @@ -1821,12 +1821,24 @@ dependencies = [ name = "eth2_ssz" version = "0.4.1" dependencies = [ - "eth2_ssz_derive", + "eth2_ssz_derive 0.4.0", "ethereum-types 0.12.1", "itertools", "smallvec", ] +[[package]] +name = "eth2_ssz_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "635b86d2c941bb71e7419a571e1763d65c93e51a1bafc400352e3bef6ff59fc9" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "eth2_ssz_derive" version = "0.4.0" @@ -2241,7 +2253,7 @@ version = "0.1.0" dependencies = [ "beacon_chain", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "proto_array", "slog", "state_processing", @@ -3661,7 +3673,7 @@ dependencies = [ "discv5", "error-chain", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "exit-future", "fnv", @@ -4421,7 +4433,7 @@ dependencies = [ "bitvec 1.0.1", "derivative", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "itertools", "lazy_static", "lighthouse_metrics", @@ -5008,7 +5020,7 @@ name = "proto_array" version = "0.2.0" dependencies = [ "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "serde", "serde_derive", "serde_yaml", @@ -5981,7 +5993,7 @@ dependencies = [ "bincode", "byteorder", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "filesystem", "flate2", "lazy_static", @@ -6268,7 +6280,7 @@ dependencies = [ "env_logger 0.9.0", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "int_to_bytes", "integer-sqrt", @@ -6310,7 +6322,7 @@ dependencies = [ "db-key", "directory", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "itertools", "lazy_static", "leveldb", @@ -6947,7 +6959,7 @@ dependencies = [ "beacon_chain", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "ethereum-types 0.12.1", "rand 0.8.5", "smallvec", @@ -7086,7 +7098,7 @@ dependencies = [ "eth2_interop_keypairs", "eth2_serde_utils", "eth2_ssz", - "eth2_ssz_derive", + "eth2_ssz_derive 0.3.0", "eth2_ssz_types", "ethereum-types 0.12.1", "hex", diff --git a/beacon_node/beacon_chain/Cargo.toml b/beacon_node/beacon_chain/Cargo.toml index 0939576c470..dd185ac7571 100644 --- a/beacon_node/beacon_chain/Cargo.toml +++ b/beacon_node/beacon_chain/Cargo.toml @@ -33,7 +33,7 @@ slot_clock = { path = "../../common/slot_clock" } eth2_hashing = "0.3.0" eth2_ssz = "0.4.1" eth2_ssz_types = "0.2.2" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" state_processing = { path = "../../consensus/state_processing" } tree_hash = "0.4.1" types = { path = "../../consensus/types" } diff --git a/beacon_node/eth1/Cargo.toml b/beacon_node/eth1/Cargo.toml index 2ee8ac6cdbc..930301256c6 100644 --- a/beacon_node/eth1/Cargo.toml +++ b/beacon_node/eth1/Cargo.toml @@ -21,7 +21,7 @@ hex = "0.4.2" types = { path = "../../consensus/types"} merkle_proof = { path = "../../consensus/merkle_proof"} eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" tree_hash = "0.4.1" parking_lot = "0.12.0" slog = "2.5.2" diff --git a/beacon_node/lighthouse_network/Cargo.toml b/beacon_node/lighthouse_network/Cargo.toml index f7745ea4097..e5af0a74999 100644 --- a/beacon_node/lighthouse_network/Cargo.toml +++ b/beacon_node/lighthouse_network/Cargo.toml @@ -12,7 +12,7 @@ eth2_ssz_types = "0.2.2" serde = { version = "1.0.116", features = ["derive"] } serde_derive = "1.0.116" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" slog = { version = "2.5.2", features = ["max_level_trace"] } lighthouse_version = { path = "../../common/lighthouse_version" } tokio = { version = "1.14.0", features = ["time", "macros"] } diff --git a/beacon_node/lighthouse_network/src/rpc/methods.rs b/beacon_node/lighthouse_network/src/rpc/methods.rs index 46f69dfc166..26d755a6e06 100644 --- a/beacon_node/lighthouse_network/src/rpc/methods.rs +++ b/beacon_node/lighthouse_network/src/rpc/methods.rs @@ -93,7 +93,7 @@ pub struct Ping { )] #[derive(Clone, Debug, PartialEq, Serialize, Encode)] #[serde(bound = "T: EthSpec")] -#[ssz(transparent)] +#[ssz(enum_behaviour = "transparent")] pub struct MetaData { /// A sequential counter indicating when data gets modified. pub seq_number: u64, diff --git a/beacon_node/operation_pool/Cargo.toml b/beacon_node/operation_pool/Cargo.toml index 997589e13bc..1d67ecdccc2 100644 --- a/beacon_node/operation_pool/Cargo.toml +++ b/beacon_node/operation_pool/Cargo.toml @@ -13,7 +13,7 @@ parking_lot = "0.12.0" types = { path = "../../consensus/types" } state_processing = { path = "../../consensus/state_processing" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" rayon = "1.5.0" serde = "1.0.116" serde_derive = "1.0.116" diff --git a/beacon_node/store/Cargo.toml b/beacon_node/store/Cargo.toml index 5c3675b2090..20ae37b3b14 100644 --- a/beacon_node/store/Cargo.toml +++ b/beacon_node/store/Cargo.toml @@ -14,7 +14,7 @@ leveldb = { version = "0.8.6", default-features = false } parking_lot = "0.12.0" itertools = "0.10.0" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" types = { path = "../../consensus/types" } state_processing = { path = "../../consensus/state_processing" } slog = "2.5.2" diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index decd396cc55..010796afd5b 100644 --- a/beacon_node/store/src/partial_beacon_state.rs +++ b/beacon_node/store/src/partial_beacon_state.rs @@ -18,7 +18,7 @@ use types::*; variant_attributes(derive(Debug, PartialEq, Clone, Encode, Decode)) )] #[derive(Debug, PartialEq, Clone, Encode)] -#[ssz(transparent)] +#[ssz(enum_behaviour = "transparent")] pub struct PartialBeaconState where T: EthSpec, diff --git a/common/eth2/Cargo.toml b/common/eth2/Cargo.toml index 74b44eab5f0..294f8ec8a3d 100644 --- a/common/eth2/Cargo.toml +++ b/common/eth2/Cargo.toml @@ -21,7 +21,7 @@ bytes = "1.0.1" account_utils = { path = "../../common/account_utils" } sensitive_url = { path = "../../common/sensitive_url" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" futures-util = "0.3.8" futures = "0.3.8" store = { path = "../../beacon_node/store", optional = true } diff --git a/consensus/cached_tree_hash/Cargo.toml b/consensus/cached_tree_hash/Cargo.toml index f8e63fd44dd..f9433e4a496 100644 --- a/consensus/cached_tree_hash/Cargo.toml +++ b/consensus/cached_tree_hash/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" ethereum-types = "0.12.1" eth2_ssz_types = "0.2.2" eth2_hashing = "0.3.0" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" eth2_ssz = "0.4.1" tree_hash = "0.4.1" smallvec = "1.6.1" diff --git a/consensus/fork_choice/Cargo.toml b/consensus/fork_choice/Cargo.toml index ddc9ab47076..52a738351ef 100644 --- a/consensus/fork_choice/Cargo.toml +++ b/consensus/fork_choice/Cargo.toml @@ -11,7 +11,7 @@ types = { path = "../types" } state_processing = { path = "../state_processing" } proto_array = { path = "../proto_array" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" slog = { version = "2.5.2", features = ["max_level_trace", "release_max_level_trace"] } [dev-dependencies] diff --git a/consensus/proto_array/Cargo.toml b/consensus/proto_array/Cargo.toml index e72279432fa..ad79ecc1e6b 100644 --- a/consensus/proto_array/Cargo.toml +++ b/consensus/proto_array/Cargo.toml @@ -11,7 +11,7 @@ path = "src/bin.rs" [dependencies] types = { path = "../types" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" serde = "1.0.116" serde_derive = "1.0.116" serde_yaml = "0.8.13" diff --git a/consensus/proto_array/src/proto_array_fork_choice.rs b/consensus/proto_array/src/proto_array_fork_choice.rs index 0ebc286fc5a..8f5d062ec6a 100644 --- a/consensus/proto_array/src/proto_array_fork_choice.rs +++ b/consensus/proto_array/src/proto_array_fork_choice.rs @@ -24,7 +24,7 @@ pub struct VoteTracker { /// Represents the verification status of an execution payload. #[derive(Clone, Copy, Debug, PartialEq, Encode, Decode, Serialize, Deserialize)] -#[ssz(union)] +#[ssz(enum_behaviour = "union")] pub enum ExecutionStatus { /// An EL has determined that the payload is valid. Valid(ExecutionBlockHash), diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index b62996fc5f6..cf97acb5029 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -167,18 +167,15 @@ impl Config { fn read(item: &DeriveInput) -> Self { let opts = StructOpts::from_derive_input(item).unwrap(); - if opts.enum_behaviour.is_some() { - panic!( + let enum_behaviour = match (opts.transparent, opts.union, &opts.enum_behaviour) { + (false, false, None) => EnumBehaviour::Unspecified, + (true, false, None) => EnumBehaviour::Transparent, + (false, true, None) => EnumBehaviour::Union, + (true, true, _) => panic!("cannot provide both \"transparent\" and \"union\""), + (_, _, Some(_)) => panic!( "the \"enum_behaviour\" attribute has been removed, please use \ either #[ssz(transparent)] or #[ssz(union)] instead" - ) - } - - let enum_behaviour = match (opts.transparent, opts.union) { - (true, true) => panic!("cannot provide both \"transparent\" and \"union\""), - (false, false) => EnumBehaviour::Unspecified, - (true, false) => EnumBehaviour::Transparent, - (false, true) => EnumBehaviour::Union, + ), }; // Don't allow `enum_behaviour` for structs. diff --git a/consensus/state_processing/Cargo.toml b/consensus/state_processing/Cargo.toml index f9710f7cc85..46ac2bae577 100644 --- a/consensus/state_processing/Cargo.toml +++ b/consensus/state_processing/Cargo.toml @@ -14,7 +14,7 @@ bls = { path = "../../crypto/bls" } integer-sqrt = "0.1.5" itertools = "0.10.0" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" eth2_ssz_types = "0.2.2" merkle_proof = { path = "../merkle_proof" } safe_arith = { path = "../safe_arith" } diff --git a/consensus/tree_hash/Cargo.toml b/consensus/tree_hash/Cargo.toml index 26724a7b771..ab080eac065 100644 --- a/consensus/tree_hash/Cargo.toml +++ b/consensus/tree_hash/Cargo.toml @@ -12,7 +12,7 @@ tree_hash_derive = "0.4.0" types = { path = "../types" } beacon_chain = { path = "../../beacon_node/beacon_chain" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" [dependencies] ethereum-types = "0.12.1" diff --git a/consensus/types/Cargo.toml b/consensus/types/Cargo.toml index 81d70561e3c..68fdbf7990d 100644 --- a/consensus/types/Cargo.toml +++ b/consensus/types/Cargo.toml @@ -25,7 +25,7 @@ serde = {version = "1.0.116" , features = ["rc"] } serde_derive = "1.0.116" slog = "2.5.2" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" eth2_ssz_types = "0.2.2" swap_or_not_shuffle = { path = "../swap_or_not_shuffle" } test_random_derive = { path = "../../common/test_random_derive" } diff --git a/consensus/types/src/beacon_block.rs b/consensus/types/src/beacon_block.rs index 52853381b08..0ec1f9a3741 100644 --- a/consensus/types/src/beacon_block.rs +++ b/consensus/types/src/beacon_block.rs @@ -47,7 +47,7 @@ use tree_hash_derive::TreeHash; #[serde(bound = "T: EthSpec, Payload: ExecPayload")] #[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))] #[tree_hash(enum_behaviour = "transparent")] -#[ssz(transparent)] +#[ssz(enum_behaviour = "transparent")] pub struct BeaconBlock = FullPayload> { #[superstruct(getter(copy))] pub slot: Slot, diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index b11fc192c06..a5d00cdf2dd 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -198,7 +198,7 @@ impl From for Hash256 { #[serde(bound = "T: EthSpec")] #[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))] #[tree_hash(enum_behaviour = "transparent")] -#[ssz(transparent)] +#[ssz(enum_behaviour = "transparent")] pub struct BeaconState where T: EthSpec, diff --git a/consensus/types/src/signed_beacon_block.rs b/consensus/types/src/signed_beacon_block.rs index fdb5047cc89..5c40c4685c3 100644 --- a/consensus/types/src/signed_beacon_block.rs +++ b/consensus/types/src/signed_beacon_block.rs @@ -64,7 +64,7 @@ impl From for Hash256 { #[serde(bound = "E: EthSpec, Payload: ExecPayload")] #[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))] #[tree_hash(enum_behaviour = "transparent")] -#[ssz(transparent)] +#[ssz(enum_behaviour = "transparent")] pub struct SignedBeaconBlock = FullPayload> { #[superstruct(only(Base), partial_getter(rename = "message_base"))] pub message: BeaconBlockBase, diff --git a/slasher/Cargo.toml b/slasher/Cargo.toml index 406a604f2a2..0f24fe9f04f 100644 --- a/slasher/Cargo.toml +++ b/slasher/Cargo.toml @@ -13,7 +13,7 @@ lmdb = ["lmdb-rkv", "lmdb-rkv-sys"] bincode = "1.3.1" byteorder = "1.3.4" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" flate2 = { version = "1.0.14", features = ["zlib"], default-features = false } lazy_static = "1.4.0" lighthouse_metrics = { path = "../common/lighthouse_metrics" } diff --git a/testing/ef_tests/Cargo.toml b/testing/ef_tests/Cargo.toml index 73f0a7ca412..e04d671396e 100644 --- a/testing/ef_tests/Cargo.toml +++ b/testing/ef_tests/Cargo.toml @@ -23,7 +23,7 @@ serde_derive = "1.0.116" serde_repr = "0.1.6" serde_yaml = "0.8.13" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.0" tree_hash = "0.4.1" tree_hash_derive = "0.4.0" cached_tree_hash = { path = "../../consensus/cached_tree_hash" } From b81807504681fbe7fc5a52ce964b25a7ec8beb85 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 18:10:38 +1100 Subject: [PATCH 06/15] Revert "Deprecate `enum_behaviour`" This reverts commit 89b64a6f53d0f68685be88d5b60d39799d9933b5. --- Cargo.lock | 45 ++++------ consensus/ssz/Cargo.toml | 2 +- consensus/ssz/tests/tests.rs | 22 ++++- consensus/ssz_derive/Cargo.toml | 3 +- consensus/ssz_derive/src/lib.rs | 145 ++++---------------------------- 5 files changed, 54 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2be8b1a0641..4200bc27b0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,7 +393,7 @@ dependencies = [ "eth2", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "execution_layer", "exit-future", @@ -714,7 +714,7 @@ version = "0.1.0" dependencies = [ "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "ethereum-types 0.12.1", "quickcheck", @@ -1498,7 +1498,7 @@ dependencies = [ "compare_fields_derive", "derivative", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "ethereum-types 0.12.1", "fork_choice", "fs2", @@ -1661,7 +1661,7 @@ dependencies = [ "eth1_test_rig", "eth2", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "execution_layer", "futures", "hex", @@ -1705,7 +1705,7 @@ dependencies = [ "eth2_keystore", "eth2_serde_utils", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "futures", "futures-util", "libsecp256k1", @@ -1821,7 +1821,7 @@ dependencies = [ name = "eth2_ssz" version = "0.4.1" dependencies = [ - "eth2_ssz_derive 0.4.0", + "eth2_ssz_derive", "ethereum-types 0.12.1", "itertools", "smallvec", @@ -1829,22 +1829,9 @@ dependencies = [ [[package]] name = "eth2_ssz_derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "635b86d2c941bb71e7419a571e1763d65c93e51a1bafc400352e3bef6ff59fc9" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "eth2_ssz_derive" -version = "0.4.0" +version = "0.3.1" dependencies = [ "darling", - "eth2_ssz", "proc-macro2", "quote", "syn", @@ -2253,7 +2240,7 @@ version = "0.1.0" dependencies = [ "beacon_chain", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "proto_array", "slog", "state_processing", @@ -3673,7 +3660,7 @@ dependencies = [ "discv5", "error-chain", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "exit-future", "fnv", @@ -4433,7 +4420,7 @@ dependencies = [ "bitvec 1.0.1", "derivative", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "itertools", "lazy_static", "lighthouse_metrics", @@ -5020,7 +5007,7 @@ name = "proto_array" version = "0.2.0" dependencies = [ "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "serde", "serde_derive", "serde_yaml", @@ -5993,7 +5980,7 @@ dependencies = [ "bincode", "byteorder", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "filesystem", "flate2", "lazy_static", @@ -6280,7 +6267,7 @@ dependencies = [ "env_logger 0.9.0", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "int_to_bytes", "integer-sqrt", @@ -6322,7 +6309,7 @@ dependencies = [ "db-key", "directory", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "itertools", "lazy_static", "leveldb", @@ -6959,7 +6946,7 @@ dependencies = [ "beacon_chain", "eth2_hashing", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "ethereum-types 0.12.1", "rand 0.8.5", "smallvec", @@ -7098,7 +7085,7 @@ dependencies = [ "eth2_interop_keypairs", "eth2_serde_utils", "eth2_ssz", - "eth2_ssz_derive 0.3.0", + "eth2_ssz_derive", "eth2_ssz_types", "ethereum-types 0.12.1", "hex", diff --git a/consensus/ssz/Cargo.toml b/consensus/ssz/Cargo.toml index 633ffc8e941..e521853c218 100644 --- a/consensus/ssz/Cargo.toml +++ b/consensus/ssz/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" name = "ssz" [dev-dependencies] -eth2_ssz_derive = "0.4.0" +eth2_ssz_derive = "0.3.1" [dependencies] ethereum-types = "0.12.1" diff --git a/consensus/ssz/tests/tests.rs b/consensus/ssz/tests/tests.rs index 1b61b8510a7..72b71fcbf9a 100644 --- a/consensus/ssz/tests/tests.rs +++ b/consensus/ssz/tests/tests.rs @@ -387,7 +387,7 @@ mod derive_macro { } #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(union)] + #[ssz(enum_behaviour = "union")] enum TwoFixedUnion { U8(u8), U16(u16), @@ -423,24 +423,38 @@ mod derive_macro { } #[derive(PartialEq, Debug, Encode)] - #[ssz(transparent)] + #[ssz(enum_behaviour = "transparent")] enum TwoVariableTrans { A(VariableA), B(VariableB), } + #[derive(PartialEq, Debug, Encode)] + #[ssz(transparent)] + enum TwoVariableTransDirectTag { + A(VariableA), + B(VariableB), + } + #[derive(PartialEq, Debug, Encode)] struct TwoVariableTransStruct { a: TwoVariableTrans, } #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(union)] + #[ssz(enum_behaviour = "union")] enum TwoVariableUnion { A(VariableA), B(VariableB), } + #[derive(PartialEq, Debug, Encode, Decode)] + #[ssz(union)] + enum TwoVariableUnionDirectTag { + A(VariableA), + B(VariableB), + } + #[derive(PartialEq, Debug, Encode, Decode)] struct TwoVariableUnionStruct { a: TwoVariableUnion, @@ -495,7 +509,7 @@ mod derive_macro { } #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(union)] + #[ssz(enum_behaviour = "union")] enum TwoVecUnion { A(Vec), B(Vec), diff --git a/consensus/ssz_derive/Cargo.toml b/consensus/ssz_derive/Cargo.toml index 2f656a9bf24..57d65e55738 100644 --- a/consensus/ssz_derive/Cargo.toml +++ b/consensus/ssz_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eth2_ssz_derive" -version = "0.4.0" +version = "0.3.1" authors = ["Paul Hauner "] edition = "2021" description = "Procedural derive macros to accompany the eth2_ssz crate." @@ -17,4 +17,3 @@ quote = "1.0.7" darling = "0.13.0" [dev-dependencies] -eth2_ssz = "0.4.1" diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index cf97acb5029..82f15e4cfb5 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -1,127 +1,7 @@ #![recursion_limit = "256"] //! Provides procedural derive macros for the `Encode` and `Decode` traits of the `eth2_ssz` crate. //! -//! ## Struct Attributes -//! -//! The following struct attributes are available: -//! -//! - `#[ssz(union)]` -//! - For `enum`, implements `ssz::Encode` and `ssz::Decode` such that the union variant is -//! encoded as a single byte in the SSZ vector. -//! - Not supported for `struct`. -//! - `#[ssz(transparent)]` -//! - For `enum`, implements `ssz::Encode` such that the `enum` is ignored. `ssz::Decode` is not -//! supported. -//! - For `struct`, implements `ssz::Encode` and `ssz::Decode` such that the outermost `struct` -//! is ignored for encoding and decoding. This is useful for new-type wrappers. The `struct` -//! must have exactly one non-skipped field. -//! -//! ## Field Attributes -//! -//! The following field attributes are available: -//! -//! - `#[ssz(with = "module")]`: uses the methods in `module` to implement `ssz::Encode` or -//! `ssz::Decode`. This is useful when it's not possible to create an `impl` for that type -//! (perhaps it is defined in another crate). -//! - `#[ssz(skip_serializing)]`: this field will not be included in the serialized SSZ vector. -//! - `#[ssz(skip_deserializing)]`: this field will not be expected to be included in the serialized -//! SSZ vector and it will be initialized from a `Default` implementation. -//! -//! ## Examples -//! -//! ### Structs -//! -//! ```rust -//! use ssz::{Encode, Decode}; -//! use ssz_derive::{Encode, Decode}; -//! -//! /// Represented as an SSZ "list" wrapped in an SSZ "container". -//! #[derive(Debug, PartialEq, Encode, Decode)] -//! struct TypicalStruct { -//! foo: Vec -//! } -//! -//! assert_eq!( -//! TypicalStruct { foo: vec![42] }.as_ssz_bytes(), -//! vec![4, 0, 0, 0, 42] -//! ); -//! -//! assert_eq!( -//! TypicalStruct::from_ssz_bytes(&[4, 0, 0, 0, 42]).unwrap(), -//! TypicalStruct { foo: vec![42] }, -//! ); -//! -//! /// Represented as an SSZ "list" *without* an SSZ "container". -//! #[derive(Encode, Decode)] -//! #[ssz(transparent)] -//! struct NewType { -//! foo: Vec -//! } -//! -//! assert_eq!( -//! NewType { foo: vec![42] }.as_ssz_bytes(), -//! vec![42] -//! ); -//! -//! /// Represented as an SSZ "list" *without* an SSZ "container". The `bar` byte is ignored. -//! #[derive(Debug, PartialEq, Encode, Decode)] -//! #[ssz(transparent)] -//! struct NewTypeSkippedField { -//! foo: Vec, -//! #[ssz(skip_serializing, skip_deserializing)] -//! bar: u8, -//! } -//! -//! assert_eq!( -//! NewTypeSkippedField { foo: vec![42], bar: 99 }.as_ssz_bytes(), -//! vec![42] -//! ); -//! assert_eq!( -//! NewTypeSkippedField::from_ssz_bytes(&[42]).unwrap(), -//! NewTypeSkippedField { foo: vec![42], bar: 0 } -//! ); -//! ``` -//! -//! ### Enums -//! -//! ```rust -//! use ssz::{Encode, Decode}; -//! use ssz_derive::{Encode, Decode}; -//! -//! /// Represented as an SSZ "union". -//! #[derive(Debug, PartialEq, Encode, Decode)] -//! #[ssz(union)] -//! enum UnionEnum { -//! Foo(u8), -//! Bar(u8), -//! } -//! -//! assert_eq!( -//! UnionEnum::Foo(42).as_ssz_bytes(), -//! vec![0, 42] -//! ); -//! assert_eq!( -//! UnionEnum::from_ssz_bytes(&[1, 42]).unwrap(), -//! UnionEnum::Bar(42), -//! ); -//! -//! /// Represented as only the value in the enum variant. -//! #[derive(Debug, PartialEq, Encode)] -//! #[ssz(transparent)] -//! enum TransparentEnum { -//! Foo(u8), -//! Bar(Vec), -//! } -//! -//! assert_eq!( -//! TransparentEnum::Foo(42).as_ssz_bytes(), -//! vec![42] -//! ); -//! assert_eq!( -//! TransparentEnum::Bar(vec![42, 42]).as_ssz_bytes(), -//! vec![42, 42] -//! ); -//! ``` +//! Supports field attributes, see each derive macro for more information. use darling::{FromDeriveInput, FromMeta}; use proc_macro::TokenStream; @@ -133,8 +13,11 @@ use syn::{parse_macro_input, DataEnum, DataStruct, DeriveInput, Ident}; /// extensions). const MAX_UNION_SELECTOR: u8 = 127; +const ENUM_TRANSPARENT: &str = "transparent"; +const ENUM_UNION: &str = "union"; +const ENUM_VARIANTS: &[&str] = &[ENUM_TRANSPARENT, ENUM_UNION]; const NO_ENUM_BEHAVIOUR_ERROR: &str = "enums require a \"transparent\" or \"union\" attribute, \ - e.g., #[ssz(transparent)] or #[ssz(union)]"; + e.g., #[ssz(transparent)]"; #[derive(Debug, FromDeriveInput)] #[darling(attributes(ssz))] @@ -171,11 +54,18 @@ impl Config { (false, false, None) => EnumBehaviour::Unspecified, (true, false, None) => EnumBehaviour::Transparent, (false, true, None) => EnumBehaviour::Union, + (false, false, Some(behaviour_string)) => match behaviour_string.as_ref() { + ENUM_TRANSPARENT => EnumBehaviour::Transparent, + ENUM_UNION => EnumBehaviour::Union, + other => panic!( + "{} is an invalid enum_behaviour, use either {:?}", + other, ENUM_VARIANTS + ), + }, (true, true, _) => panic!("cannot provide both \"transparent\" and \"union\""), - (_, _, Some(_)) => panic!( - "the \"enum_behaviour\" attribute has been removed, please use \ - either #[ssz(transparent)] or #[ssz(union)] instead" - ), + (_, _, Some(_)) => { + panic!("\"enum_behaviour\" cannot be used with \"transparent\" or \"union\"") + } }; // Don't allow `enum_behaviour` for structs. @@ -580,7 +470,8 @@ pub fn ssz_decode_derive(input: TokenStream) -> TokenStream { syn::Data::Enum(s) => match config.enum_behaviour { EnumBehaviour::Union => ssz_decode_derive_enum_union(&item, s), EnumBehaviour::Transparent => panic!( - "Decode cannot be derived for enum_behaviour \"transparent\", only \"union\" is valid." + "Decode cannot be derived for enum_behaviour \"{}\", only \"{}\" is valid.", + ENUM_TRANSPARENT, ENUM_UNION ), EnumBehaviour::Unspecified => panic!("{}", NO_ENUM_BEHAVIOUR_ERROR), }, From e23ffae2dfa7803a3b4ab099ac817e0b56e21682 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 18:46:16 +1100 Subject: [PATCH 07/15] Add `struct_behaviour` --- Cargo.lock | 1 + consensus/ssz/tests/tests.rs | 18 +-- consensus/ssz_derive/Cargo.toml | 1 + consensus/ssz_derive/src/lib.rs | 269 +++++++++++++++++++++++--------- 4 files changed, 201 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4200bc27b0d..98e0a17a6e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1832,6 +1832,7 @@ name = "eth2_ssz_derive" version = "0.3.1" dependencies = [ "darling", + "eth2_ssz", "proc-macro2", "quote", "syn", diff --git a/consensus/ssz/tests/tests.rs b/consensus/ssz/tests/tests.rs index 72b71fcbf9a..af259cd5b5c 100644 --- a/consensus/ssz/tests/tests.rs +++ b/consensus/ssz/tests/tests.rs @@ -429,13 +429,6 @@ mod derive_macro { B(VariableB), } - #[derive(PartialEq, Debug, Encode)] - #[ssz(transparent)] - enum TwoVariableTransDirectTag { - A(VariableA), - B(VariableB), - } - #[derive(PartialEq, Debug, Encode)] struct TwoVariableTransStruct { a: TwoVariableTrans, @@ -448,13 +441,6 @@ mod derive_macro { B(VariableB), } - #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(union)] - enum TwoVariableUnionDirectTag { - A(VariableA), - B(VariableB), - } - #[derive(PartialEq, Debug, Encode, Decode)] struct TwoVariableUnionStruct { a: TwoVariableUnion, @@ -528,7 +514,7 @@ mod derive_macro { } #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(transparent)] + #[ssz(struct_behaviour = "transparent")] struct TransparentStruct { inner: Vec, } @@ -545,7 +531,7 @@ mod derive_macro { } #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(transparent)] + #[ssz(struct_behaviour = "transparent")] struct TransparentStructSkippedField { inner: Vec, #[ssz(skip_serializing, skip_deserializing)] diff --git a/consensus/ssz_derive/Cargo.toml b/consensus/ssz_derive/Cargo.toml index 57d65e55738..d3b2865a61d 100644 --- a/consensus/ssz_derive/Cargo.toml +++ b/consensus/ssz_derive/Cargo.toml @@ -17,3 +17,4 @@ quote = "1.0.7" darling = "0.13.0" [dev-dependencies] +eth2_ssz = "0.4.1" diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index 82f15e4cfb5..3a013c476ab 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -1,7 +1,123 @@ #![recursion_limit = "256"] //! Provides procedural derive macros for the `Encode` and `Decode` traits of the `eth2_ssz` crate. //! -//! Supports field attributes, see each derive macro for more information. +//! ## Attributes +//! +//! The following struct\enum attributes are available: +//! +//! - `#[ssz(enum_behaviour = "union")]`: encodes and decodes an `enum` with a one-byte variant selector. +//! - `#[ssz(enum_behaviour = "transparent")]`: allows encoding an `enum` by serializing only the +//! value and outermost the `enum`. +//! - `#[ssz(struct_behaviour = "container")]`: encodes and decodes the `struct` as an SSZ +//! "container". +//! - `#[ssz(struct_behaviour = "transparent")]`: encodes and decodes a `struct` with exactly one +//! non-skipped field as if the outermost `struct` does not exist. +//! +//! The following field attributes are available: +//! +//! - `#[ssz(with = "module")]`: uses the methods in `module` to implement `ssz::Encode` or +//! `ssz::Decode`. This is useful when it's not possible to create an `impl` for that type +//! (e.g. it is defined in another crate). +//! - `#[ssz(skip_serializing)]`: this field will not be included in the serialized SSZ vector. +//! - `#[ssz(skip_deserializing)]`: this field will not be expected to be included in the serialized +//! SSZ vector and it will be initialized from a `Default` implementation. +//! +//! ## Examples +//! +//! ### Structs +//! +//! ```rust +//! use ssz::{Encode, Decode}; +//! use ssz_derive::{Encode, Decode}; +//! +//! /// Represented as an SSZ "list" wrapped in an SSZ "container". +//! #[derive(Debug, PartialEq, Encode, Decode)] +//! #[ssz(struct_behaviour = "container")] // "container" is the default behaviour +//! struct TypicalStruct { +//! foo: Vec +//! } +//! +//! assert_eq!( +//! TypicalStruct { foo: vec![42] }.as_ssz_bytes(), +//! vec![4, 0, 0, 0, 42] +//! ); +//! +//! assert_eq!( +//! TypicalStruct::from_ssz_bytes(&[4, 0, 0, 0, 42]).unwrap(), +//! TypicalStruct { foo: vec![42] }, +//! ); +//! +//! /// Represented as an SSZ "list" *without* an SSZ "container". +//! #[derive(Encode, Decode)] +//! #[ssz(struct_behaviour = "transparent")] +//! struct NewType { +//! foo: Vec +//! } +//! +//! assert_eq!( +//! NewType { foo: vec![42] }.as_ssz_bytes(), +//! vec![42] +//! ); +//! +//! /// Represented as an SSZ "list" *without* an SSZ "container". The `bar` byte is ignored. +//! #[derive(Debug, PartialEq, Encode, Decode)] +//! #[ssz(struct_behaviour = "transparent")] +//! struct NewTypeSkippedField { +//! foo: Vec, +//! #[ssz(skip_serializing, skip_deserializing)] +//! bar: u8, +//! } +//! +//! assert_eq!( +//! NewTypeSkippedField { foo: vec![42], bar: 99 }.as_ssz_bytes(), +//! vec![42] +//! ); +//! assert_eq!( +//! NewTypeSkippedField::from_ssz_bytes(&[42]).unwrap(), +//! NewTypeSkippedField { foo: vec![42], bar: 0 } +//! ); +//! ``` +//! +//! ### Enums +//! +//! ```rust +//! use ssz::{Encode, Decode}; +//! use ssz_derive::{Encode, Decode}; +//! +//! /// Represented as an SSZ "union". +//! #[derive(Debug, PartialEq, Encode, Decode)] +//! #[ssz(enum_behaviour = "union")] +//! enum UnionEnum { +//! Foo(u8), +//! Bar(u8), +//! } +//! +//! assert_eq!( +//! UnionEnum::Foo(42).as_ssz_bytes(), +//! vec![0, 42] +//! ); +//! assert_eq!( +//! UnionEnum::from_ssz_bytes(&[1, 42]).unwrap(), +//! UnionEnum::Bar(42), +//! ); +//! +//! /// Represented as only the value in the enum variant. +//! #[derive(Debug, PartialEq, Encode)] +//! #[ssz(enum_behaviour = "transparent")] +//! enum TransparentEnum { +//! Foo(u8), +//! Bar(Vec), +//! } +//! +//! assert_eq!( +//! TransparentEnum::Foo(42).as_ssz_bytes(), +//! vec![42] +//! ); +//! assert_eq!( +//! TransparentEnum::Bar(vec![42, 42]).as_ssz_bytes(), +//! vec![42, 42] +//! ); +//! ``` use darling::{FromDeriveInput, FromMeta}; use proc_macro::TokenStream; @@ -15,9 +131,8 @@ const MAX_UNION_SELECTOR: u8 = 127; const ENUM_TRANSPARENT: &str = "transparent"; const ENUM_UNION: &str = "union"; -const ENUM_VARIANTS: &[&str] = &[ENUM_TRANSPARENT, ENUM_UNION]; -const NO_ENUM_BEHAVIOUR_ERROR: &str = "enums require a \"transparent\" or \"union\" attribute, \ - e.g., #[ssz(transparent)]"; +const NO_ENUM_BEHAVIOUR_ERROR: &str = "enums require an \"enum_behaviour\" attribute with \ + a \"transparent\" or \"union\" value, e.g., #[ssz(enum_behaviour = \"transparent\")]"; #[derive(Debug, FromDeriveInput)] #[darling(attributes(ssz))] @@ -25,9 +140,7 @@ struct StructOpts { #[darling(default)] enum_behaviour: Option, #[darling(default)] - transparent: bool, - #[darling(default)] - union: bool, + struct_behaviour: Option, } /// Field-level configuration. @@ -41,60 +154,76 @@ struct FieldOpts { skip_deserializing: bool, } -struct Config { - struct_behaviour: StructBehaviour, - enum_behaviour: EnumBehaviour, -} - -impl Config { - fn read(item: &DeriveInput) -> Self { - let opts = StructOpts::from_derive_input(item).unwrap(); - - let enum_behaviour = match (opts.transparent, opts.union, &opts.enum_behaviour) { - (false, false, None) => EnumBehaviour::Unspecified, - (true, false, None) => EnumBehaviour::Transparent, - (false, true, None) => EnumBehaviour::Union, - (false, false, Some(behaviour_string)) => match behaviour_string.as_ref() { - ENUM_TRANSPARENT => EnumBehaviour::Transparent, - ENUM_UNION => EnumBehaviour::Union, - other => panic!( - "{} is an invalid enum_behaviour, use either {:?}", - other, ENUM_VARIANTS - ), - }, - (true, true, _) => panic!("cannot provide both \"transparent\" and \"union\""), - (_, _, Some(_)) => { - panic!("\"enum_behaviour\" cannot be used with \"transparent\" or \"union\"") - } - }; - - // Don't allow `enum_behaviour` for structs. - if matches!(item.data, syn::Data::Struct(_)) && opts.enum_behaviour.is_some() { - panic!("cannot provide \"enum_behaviour\" for a struct") - } - - let struct_behaviour = if opts.transparent { - StructBehaviour::Transparent - } else { - StructBehaviour::Container - }; - - Self { - struct_behaviour, - enum_behaviour, - } - } +enum Procedure<'a> { + Struct { + data: &'a syn::DataStruct, + behaviour: StructBehaviour, + }, + Enum { + data: &'a syn::DataEnum, + behaviour: EnumBehaviour, + }, } enum StructBehaviour { - Transparent, Container, + Transparent, } enum EnumBehaviour { - Transparent, Union, - Unspecified, + Transparent, +} + +impl<'a> Procedure<'a> { + fn read(item: &'a DeriveInput) -> Self { + let opts = StructOpts::from_derive_input(item).unwrap(); + + match &item.data { + syn::Data::Struct(data) => { + if opts.enum_behaviour.is_some() { + panic!("cannot use \"enum_behaviour\" for a struct"); + } + + match opts.struct_behaviour.as_deref() { + Some("container") | None => Procedure::Struct { + data, + behaviour: StructBehaviour::Container, + }, + Some("transparent") => Procedure::Struct { + data, + behaviour: StructBehaviour::Transparent, + }, + Some(other) => panic!( + "{} is not a valid struct behaviour, use \"container\" or \"transparent\"", + other + ), + } + } + syn::Data::Enum(data) => { + if opts.struct_behaviour.is_some() { + panic!("cannot use \"struct_behaviour\" for an enum"); + } + + match opts.enum_behaviour.as_deref() { + Some("union") => Procedure::Enum { + data, + behaviour: EnumBehaviour::Union, + }, + Some("transparent") => Procedure::Enum { + data, + behaviour: EnumBehaviour::Transparent, + }, + Some(other) => panic!( + "{} is not a valid struct behaviour, use \"container\" or \"transparent\"", + other + ), + None => panic!("{}", NO_ENUM_BEHAVIOUR_ERROR), + } + } + _ => panic!("ssz_derive only supports structs and enums"), + } + } } fn parse_ssz_fields(struct_data: &syn::DataStruct) -> Vec<(&syn::Type, &syn::Ident, FieldOpts)> { @@ -135,19 +264,17 @@ fn parse_ssz_fields(struct_data: &syn::DataStruct) -> Vec<(&syn::Type, &syn::Ide #[proc_macro_derive(Encode, attributes(ssz))] pub fn ssz_encode_derive(input: TokenStream) -> TokenStream { let item = parse_macro_input!(input as DeriveInput); - let config = Config::read(&item); + let procedure = Procedure::read(&item); - match &item.data { - syn::Data::Struct(s) => match config.struct_behaviour { - StructBehaviour::Transparent => ssz_encode_derive_struct_transparent(&item, s), - StructBehaviour::Container => ssz_encode_derive_struct(&item, s), + match procedure { + Procedure::Struct { data, behaviour } => match behaviour { + StructBehaviour::Transparent => ssz_encode_derive_struct_transparent(&item, data), + StructBehaviour::Container => ssz_encode_derive_struct(&item, data), }, - syn::Data::Enum(s) => match config.enum_behaviour { - EnumBehaviour::Transparent => ssz_encode_derive_enum_transparent(&item, s), - EnumBehaviour::Union => ssz_encode_derive_enum_union(&item, s), - EnumBehaviour::Unspecified => panic!("{}", NO_ENUM_BEHAVIOUR_ERROR), + Procedure::Enum { data, behaviour } => match behaviour { + EnumBehaviour::Transparent => ssz_encode_derive_enum_transparent(&item, data), + EnumBehaviour::Union => ssz_encode_derive_enum_union(&item, data), }, - _ => panic!("ssz_derive only supports structs and enums"), } } @@ -460,22 +587,20 @@ fn ssz_encode_derive_enum_union(derive_input: &DeriveInput, enum_data: &DataEnum #[proc_macro_derive(Decode, attributes(ssz))] pub fn ssz_decode_derive(input: TokenStream) -> TokenStream { let item = parse_macro_input!(input as DeriveInput); - let config = Config::read(&item); + let procedure = Procedure::read(&item); - match &item.data { - syn::Data::Struct(s) => match config.struct_behaviour { - StructBehaviour::Transparent => ssz_decode_derive_struct_transparent(&item, s), - StructBehaviour::Container => ssz_decode_derive_struct(&item, s), + match procedure { + Procedure::Struct { data, behaviour } => match behaviour { + StructBehaviour::Transparent => ssz_decode_derive_struct_transparent(&item, data), + StructBehaviour::Container => ssz_decode_derive_struct(&item, data), }, - syn::Data::Enum(s) => match config.enum_behaviour { - EnumBehaviour::Union => ssz_decode_derive_enum_union(&item, s), + Procedure::Enum { data, behaviour } => match behaviour { + EnumBehaviour::Union => ssz_decode_derive_enum_union(&item, data), EnumBehaviour::Transparent => panic!( "Decode cannot be derived for enum_behaviour \"{}\", only \"{}\" is valid.", ENUM_TRANSPARENT, ENUM_UNION ), - EnumBehaviour::Unspecified => panic!("{}", NO_ENUM_BEHAVIOUR_ERROR), }, - _ => panic!("ssz_derive only supports structs and enums"), } } From 2276bfc9b234a9fa10732086a748db5e75908997 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 19:27:35 +1100 Subject: [PATCH 08/15] Tidy --- consensus/ssz_derive/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index 3a013c476ab..a0d485d8e71 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -7,7 +7,7 @@ //! //! - `#[ssz(enum_behaviour = "union")]`: encodes and decodes an `enum` with a one-byte variant selector. //! - `#[ssz(enum_behaviour = "transparent")]`: allows encoding an `enum` by serializing only the -//! value and outermost the `enum`. +//! value whilst ignoring outermost the `enum`. //! - `#[ssz(struct_behaviour = "container")]`: encodes and decodes the `struct` as an SSZ //! "container". //! - `#[ssz(struct_behaviour = "transparent")]`: encodes and decodes a `struct` with exactly one @@ -89,7 +89,7 @@ //! #[ssz(enum_behaviour = "union")] //! enum UnionEnum { //! Foo(u8), -//! Bar(u8), +//! Bar(Vec), //! } //! //! assert_eq!( @@ -97,8 +97,8 @@ //! vec![0, 42] //! ); //! assert_eq!( -//! UnionEnum::from_ssz_bytes(&[1, 42]).unwrap(), -//! UnionEnum::Bar(42), +//! UnionEnum::from_ssz_bytes(&[1, 42, 42]).unwrap(), +//! UnionEnum::Bar(vec![42, 42]), //! ); //! //! /// Represented as only the value in the enum variant. From 256a6c03d2fe74d551a0c24a9f9568016b694f2d Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 19:27:47 +1100 Subject: [PATCH 09/15] Move tests into `ssz_derive` --- consensus/ssz/tests/tests.rs | 185 ---------------------------- consensus/ssz_derive/tests/tests.rs | 182 +++++++++++++++++++++++++++ 2 files changed, 182 insertions(+), 185 deletions(-) create mode 100644 consensus/ssz_derive/tests/tests.rs diff --git a/consensus/ssz/tests/tests.rs b/consensus/ssz/tests/tests.rs index af259cd5b5c..355cf35b582 100644 --- a/consensus/ssz/tests/tests.rs +++ b/consensus/ssz/tests/tests.rs @@ -370,188 +370,3 @@ mod round_trip { round_trip(data); } } - -mod derive_macro { - use ssz::{Decode, Encode}; - use ssz_derive::{Decode, Encode}; - use std::fmt::Debug; - use std::marker::PhantomData; - - fn assert_encode(item: &T, bytes: &[u8]) { - assert_eq!(item.as_ssz_bytes(), bytes); - } - - fn assert_encode_decode(item: &T, bytes: &[u8]) { - assert_encode(item, bytes); - assert_eq!(T::from_ssz_bytes(bytes).unwrap(), *item); - } - - #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(enum_behaviour = "union")] - enum TwoFixedUnion { - U8(u8), - U16(u16), - } - - #[derive(PartialEq, Debug, Encode, Decode)] - struct TwoFixedUnionStruct { - a: TwoFixedUnion, - } - - #[test] - fn two_fixed_union() { - let eight = TwoFixedUnion::U8(1); - let sixteen = TwoFixedUnion::U16(1); - - assert_encode_decode(&eight, &[0, 1]); - assert_encode_decode(&sixteen, &[1, 1, 0]); - - assert_encode_decode(&TwoFixedUnionStruct { a: eight }, &[4, 0, 0, 0, 0, 1]); - assert_encode_decode(&TwoFixedUnionStruct { a: sixteen }, &[4, 0, 0, 0, 1, 1, 0]); - } - - #[derive(PartialEq, Debug, Encode, Decode)] - struct VariableA { - a: u8, - b: Vec, - } - - #[derive(PartialEq, Debug, Encode, Decode)] - struct VariableB { - a: Vec, - b: u8, - } - - #[derive(PartialEq, Debug, Encode)] - #[ssz(enum_behaviour = "transparent")] - enum TwoVariableTrans { - A(VariableA), - B(VariableB), - } - - #[derive(PartialEq, Debug, Encode)] - struct TwoVariableTransStruct { - a: TwoVariableTrans, - } - - #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(enum_behaviour = "union")] - enum TwoVariableUnion { - A(VariableA), - B(VariableB), - } - - #[derive(PartialEq, Debug, Encode, Decode)] - struct TwoVariableUnionStruct { - a: TwoVariableUnion, - } - - #[test] - fn two_variable_trans() { - let trans_a = TwoVariableTrans::A(VariableA { - a: 1, - b: vec![2, 3], - }); - let trans_b = TwoVariableTrans::B(VariableB { - a: vec![1, 2], - b: 3, - }); - - assert_encode(&trans_a, &[1, 5, 0, 0, 0, 2, 3]); - assert_encode(&trans_b, &[5, 0, 0, 0, 3, 1, 2]); - - assert_encode( - &TwoVariableTransStruct { a: trans_a }, - &[4, 0, 0, 0, 1, 5, 0, 0, 0, 2, 3], - ); - assert_encode( - &TwoVariableTransStruct { a: trans_b }, - &[4, 0, 0, 0, 5, 0, 0, 0, 3, 1, 2], - ); - } - - #[test] - fn two_variable_union() { - let union_a = TwoVariableUnion::A(VariableA { - a: 1, - b: vec![2, 3], - }); - let union_b = TwoVariableUnion::B(VariableB { - a: vec![1, 2], - b: 3, - }); - - assert_encode_decode(&union_a, &[0, 1, 5, 0, 0, 0, 2, 3]); - assert_encode_decode(&union_b, &[1, 5, 0, 0, 0, 3, 1, 2]); - - assert_encode_decode( - &TwoVariableUnionStruct { a: union_a }, - &[4, 0, 0, 0, 0, 1, 5, 0, 0, 0, 2, 3], - ); - assert_encode_decode( - &TwoVariableUnionStruct { a: union_b }, - &[4, 0, 0, 0, 1, 5, 0, 0, 0, 3, 1, 2], - ); - } - - #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(enum_behaviour = "union")] - enum TwoVecUnion { - A(Vec), - B(Vec), - } - - #[test] - fn two_vec_union() { - assert_encode_decode(&TwoVecUnion::A(vec![]), &[0]); - assert_encode_decode(&TwoVecUnion::B(vec![]), &[1]); - - assert_encode_decode(&TwoVecUnion::A(vec![0]), &[0, 0]); - assert_encode_decode(&TwoVecUnion::B(vec![0]), &[1, 0]); - - assert_encode_decode(&TwoVecUnion::A(vec![0, 1]), &[0, 0, 1]); - assert_encode_decode(&TwoVecUnion::B(vec![0, 1]), &[1, 0, 1]); - } - - #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(struct_behaviour = "transparent")] - struct TransparentStruct { - inner: Vec, - } - - impl TransparentStruct { - fn new(inner: u8) -> Self { - Self { inner: vec![inner] } - } - } - - #[test] - fn transparent_struct() { - assert_encode_decode(&TransparentStruct::new(42), &vec![42_u8].as_ssz_bytes()); - } - - #[derive(PartialEq, Debug, Encode, Decode)] - #[ssz(struct_behaviour = "transparent")] - struct TransparentStructSkippedField { - inner: Vec, - #[ssz(skip_serializing, skip_deserializing)] - skipped: PhantomData, - } - - impl TransparentStructSkippedField { - fn new(inner: u8) -> Self { - Self { - inner: vec![inner], - skipped: PhantomData, - } - } - } - - #[test] - fn transparent_struct_skipped_field() { - assert_encode_decode( - &TransparentStructSkippedField::new(42), - &vec![42_u8].as_ssz_bytes(), - ); - } -} diff --git a/consensus/ssz_derive/tests/tests.rs b/consensus/ssz_derive/tests/tests.rs new file mode 100644 index 00000000000..137e491a28e --- /dev/null +++ b/consensus/ssz_derive/tests/tests.rs @@ -0,0 +1,182 @@ +use ssz::{Decode, Encode}; +use ssz_derive::{Decode, Encode}; +use std::fmt::Debug; +use std::marker::PhantomData; + +fn assert_encode(item: &T, bytes: &[u8]) { + assert_eq!(item.as_ssz_bytes(), bytes); +} + +fn assert_encode_decode(item: &T, bytes: &[u8]) { + assert_encode(item, bytes); + assert_eq!(T::from_ssz_bytes(bytes).unwrap(), *item); +} + +#[derive(PartialEq, Debug, Encode, Decode)] +#[ssz(enum_behaviour = "union")] +enum TwoFixedUnion { + U8(u8), + U16(u16), +} + +#[derive(PartialEq, Debug, Encode, Decode)] +struct TwoFixedUnionStruct { + a: TwoFixedUnion, +} + +#[test] +fn two_fixed_union() { + let eight = TwoFixedUnion::U8(1); + let sixteen = TwoFixedUnion::U16(1); + + assert_encode_decode(&eight, &[0, 1]); + assert_encode_decode(&sixteen, &[1, 1, 0]); + + assert_encode_decode(&TwoFixedUnionStruct { a: eight }, &[4, 0, 0, 0, 0, 1]); + assert_encode_decode(&TwoFixedUnionStruct { a: sixteen }, &[4, 0, 0, 0, 1, 1, 0]); +} + +#[derive(PartialEq, Debug, Encode, Decode)] +struct VariableA { + a: u8, + b: Vec, +} + +#[derive(PartialEq, Debug, Encode, Decode)] +struct VariableB { + a: Vec, + b: u8, +} + +#[derive(PartialEq, Debug, Encode)] +#[ssz(enum_behaviour = "transparent")] +enum TwoVariableTrans { + A(VariableA), + B(VariableB), +} + +#[derive(PartialEq, Debug, Encode)] +struct TwoVariableTransStruct { + a: TwoVariableTrans, +} + +#[derive(PartialEq, Debug, Encode, Decode)] +#[ssz(enum_behaviour = "union")] +enum TwoVariableUnion { + A(VariableA), + B(VariableB), +} + +#[derive(PartialEq, Debug, Encode, Decode)] +struct TwoVariableUnionStruct { + a: TwoVariableUnion, +} + +#[test] +fn two_variable_trans() { + let trans_a = TwoVariableTrans::A(VariableA { + a: 1, + b: vec![2, 3], + }); + let trans_b = TwoVariableTrans::B(VariableB { + a: vec![1, 2], + b: 3, + }); + + assert_encode(&trans_a, &[1, 5, 0, 0, 0, 2, 3]); + assert_encode(&trans_b, &[5, 0, 0, 0, 3, 1, 2]); + + assert_encode( + &TwoVariableTransStruct { a: trans_a }, + &[4, 0, 0, 0, 1, 5, 0, 0, 0, 2, 3], + ); + assert_encode( + &TwoVariableTransStruct { a: trans_b }, + &[4, 0, 0, 0, 5, 0, 0, 0, 3, 1, 2], + ); +} + +#[test] +fn two_variable_union() { + let union_a = TwoVariableUnion::A(VariableA { + a: 1, + b: vec![2, 3], + }); + let union_b = TwoVariableUnion::B(VariableB { + a: vec![1, 2], + b: 3, + }); + + assert_encode_decode(&union_a, &[0, 1, 5, 0, 0, 0, 2, 3]); + assert_encode_decode(&union_b, &[1, 5, 0, 0, 0, 3, 1, 2]); + + assert_encode_decode( + &TwoVariableUnionStruct { a: union_a }, + &[4, 0, 0, 0, 0, 1, 5, 0, 0, 0, 2, 3], + ); + assert_encode_decode( + &TwoVariableUnionStruct { a: union_b }, + &[4, 0, 0, 0, 1, 5, 0, 0, 0, 3, 1, 2], + ); +} + +#[derive(PartialEq, Debug, Encode, Decode)] +#[ssz(enum_behaviour = "union")] +enum TwoVecUnion { + A(Vec), + B(Vec), +} + +#[test] +fn two_vec_union() { + assert_encode_decode(&TwoVecUnion::A(vec![]), &[0]); + assert_encode_decode(&TwoVecUnion::B(vec![]), &[1]); + + assert_encode_decode(&TwoVecUnion::A(vec![0]), &[0, 0]); + assert_encode_decode(&TwoVecUnion::B(vec![0]), &[1, 0]); + + assert_encode_decode(&TwoVecUnion::A(vec![0, 1]), &[0, 0, 1]); + assert_encode_decode(&TwoVecUnion::B(vec![0, 1]), &[1, 0, 1]); +} + +#[derive(PartialEq, Debug, Encode, Decode)] +#[ssz(struct_behaviour = "transparent")] +struct TransparentStruct { + inner: Vec, +} + +impl TransparentStruct { + fn new(inner: u8) -> Self { + Self { inner: vec![inner] } + } +} + +#[test] +fn transparent_struct() { + assert_encode_decode(&TransparentStruct::new(42), &vec![42_u8].as_ssz_bytes()); +} + +#[derive(PartialEq, Debug, Encode, Decode)] +#[ssz(struct_behaviour = "transparent")] +struct TransparentStructSkippedField { + inner: Vec, + #[ssz(skip_serializing, skip_deserializing)] + skipped: PhantomData, +} + +impl TransparentStructSkippedField { + fn new(inner: u8) -> Self { + Self { + inner: vec![inner], + skipped: PhantomData, + } + } +} + +#[test] +fn transparent_struct_skipped_field() { + assert_encode_decode( + &TransparentStructSkippedField::new(42), + &vec![42_u8].as_ssz_bytes(), + ); +} From ea1a10d86eabab145ace914949a2636fe86989af Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 19:34:40 +1100 Subject: [PATCH 10/15] Bump ssz derive --- beacon_node/beacon_chain/Cargo.toml | 2 +- beacon_node/eth1/Cargo.toml | 2 +- beacon_node/lighthouse_network/Cargo.toml | 2 +- beacon_node/operation_pool/Cargo.toml | 2 +- beacon_node/store/Cargo.toml | 2 +- common/eth2/Cargo.toml | 2 +- consensus/cached_tree_hash/Cargo.toml | 2 +- consensus/fork_choice/Cargo.toml | 2 +- consensus/proto_array/Cargo.toml | 2 +- consensus/state_processing/Cargo.toml | 2 +- consensus/tree_hash/Cargo.toml | 2 +- consensus/types/Cargo.toml | 2 +- slasher/Cargo.toml | 2 +- testing/ef_tests/Cargo.toml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/beacon_node/beacon_chain/Cargo.toml b/beacon_node/beacon_chain/Cargo.toml index dd185ac7571..5b85833048b 100644 --- a/beacon_node/beacon_chain/Cargo.toml +++ b/beacon_node/beacon_chain/Cargo.toml @@ -33,7 +33,7 @@ slot_clock = { path = "../../common/slot_clock" } eth2_hashing = "0.3.0" eth2_ssz = "0.4.1" eth2_ssz_types = "0.2.2" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" state_processing = { path = "../../consensus/state_processing" } tree_hash = "0.4.1" types = { path = "../../consensus/types" } diff --git a/beacon_node/eth1/Cargo.toml b/beacon_node/eth1/Cargo.toml index 930301256c6..979ef931791 100644 --- a/beacon_node/eth1/Cargo.toml +++ b/beacon_node/eth1/Cargo.toml @@ -21,7 +21,7 @@ hex = "0.4.2" types = { path = "../../consensus/types"} merkle_proof = { path = "../../consensus/merkle_proof"} eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" tree_hash = "0.4.1" parking_lot = "0.12.0" slog = "2.5.2" diff --git a/beacon_node/lighthouse_network/Cargo.toml b/beacon_node/lighthouse_network/Cargo.toml index e5af0a74999..ead029b4e6d 100644 --- a/beacon_node/lighthouse_network/Cargo.toml +++ b/beacon_node/lighthouse_network/Cargo.toml @@ -12,7 +12,7 @@ eth2_ssz_types = "0.2.2" serde = { version = "1.0.116", features = ["derive"] } serde_derive = "1.0.116" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" slog = { version = "2.5.2", features = ["max_level_trace"] } lighthouse_version = { path = "../../common/lighthouse_version" } tokio = { version = "1.14.0", features = ["time", "macros"] } diff --git a/beacon_node/operation_pool/Cargo.toml b/beacon_node/operation_pool/Cargo.toml index 1d67ecdccc2..8483233589f 100644 --- a/beacon_node/operation_pool/Cargo.toml +++ b/beacon_node/operation_pool/Cargo.toml @@ -13,7 +13,7 @@ parking_lot = "0.12.0" types = { path = "../../consensus/types" } state_processing = { path = "../../consensus/state_processing" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" rayon = "1.5.0" serde = "1.0.116" serde_derive = "1.0.116" diff --git a/beacon_node/store/Cargo.toml b/beacon_node/store/Cargo.toml index 20ae37b3b14..09d960535e4 100644 --- a/beacon_node/store/Cargo.toml +++ b/beacon_node/store/Cargo.toml @@ -14,7 +14,7 @@ leveldb = { version = "0.8.6", default-features = false } parking_lot = "0.12.0" itertools = "0.10.0" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" types = { path = "../../consensus/types" } state_processing = { path = "../../consensus/state_processing" } slog = "2.5.2" diff --git a/common/eth2/Cargo.toml b/common/eth2/Cargo.toml index 294f8ec8a3d..eca086d838f 100644 --- a/common/eth2/Cargo.toml +++ b/common/eth2/Cargo.toml @@ -21,7 +21,7 @@ bytes = "1.0.1" account_utils = { path = "../../common/account_utils" } sensitive_url = { path = "../../common/sensitive_url" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" futures-util = "0.3.8" futures = "0.3.8" store = { path = "../../beacon_node/store", optional = true } diff --git a/consensus/cached_tree_hash/Cargo.toml b/consensus/cached_tree_hash/Cargo.toml index f9433e4a496..c362af83cd9 100644 --- a/consensus/cached_tree_hash/Cargo.toml +++ b/consensus/cached_tree_hash/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" ethereum-types = "0.12.1" eth2_ssz_types = "0.2.2" eth2_hashing = "0.3.0" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" eth2_ssz = "0.4.1" tree_hash = "0.4.1" smallvec = "1.6.1" diff --git a/consensus/fork_choice/Cargo.toml b/consensus/fork_choice/Cargo.toml index 52a738351ef..f0381e5ad99 100644 --- a/consensus/fork_choice/Cargo.toml +++ b/consensus/fork_choice/Cargo.toml @@ -11,7 +11,7 @@ types = { path = "../types" } state_processing = { path = "../state_processing" } proto_array = { path = "../proto_array" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" slog = { version = "2.5.2", features = ["max_level_trace", "release_max_level_trace"] } [dev-dependencies] diff --git a/consensus/proto_array/Cargo.toml b/consensus/proto_array/Cargo.toml index ad79ecc1e6b..1c7b19bf1da 100644 --- a/consensus/proto_array/Cargo.toml +++ b/consensus/proto_array/Cargo.toml @@ -11,7 +11,7 @@ path = "src/bin.rs" [dependencies] types = { path = "../types" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" serde = "1.0.116" serde_derive = "1.0.116" serde_yaml = "0.8.13" diff --git a/consensus/state_processing/Cargo.toml b/consensus/state_processing/Cargo.toml index 46ac2bae577..ccb41830be8 100644 --- a/consensus/state_processing/Cargo.toml +++ b/consensus/state_processing/Cargo.toml @@ -14,7 +14,7 @@ bls = { path = "../../crypto/bls" } integer-sqrt = "0.1.5" itertools = "0.10.0" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" eth2_ssz_types = "0.2.2" merkle_proof = { path = "../merkle_proof" } safe_arith = { path = "../safe_arith" } diff --git a/consensus/tree_hash/Cargo.toml b/consensus/tree_hash/Cargo.toml index ab080eac065..1f004724fcb 100644 --- a/consensus/tree_hash/Cargo.toml +++ b/consensus/tree_hash/Cargo.toml @@ -12,7 +12,7 @@ tree_hash_derive = "0.4.0" types = { path = "../types" } beacon_chain = { path = "../../beacon_node/beacon_chain" } eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" [dependencies] ethereum-types = "0.12.1" diff --git a/consensus/types/Cargo.toml b/consensus/types/Cargo.toml index 68fdbf7990d..bcb7daa7054 100644 --- a/consensus/types/Cargo.toml +++ b/consensus/types/Cargo.toml @@ -25,7 +25,7 @@ serde = {version = "1.0.116" , features = ["rc"] } serde_derive = "1.0.116" slog = "2.5.2" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" eth2_ssz_types = "0.2.2" swap_or_not_shuffle = { path = "../swap_or_not_shuffle" } test_random_derive = { path = "../../common/test_random_derive" } diff --git a/slasher/Cargo.toml b/slasher/Cargo.toml index 0f24fe9f04f..c5ce8793ad4 100644 --- a/slasher/Cargo.toml +++ b/slasher/Cargo.toml @@ -13,7 +13,7 @@ lmdb = ["lmdb-rkv", "lmdb-rkv-sys"] bincode = "1.3.1" byteorder = "1.3.4" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" flate2 = { version = "1.0.14", features = ["zlib"], default-features = false } lazy_static = "1.4.0" lighthouse_metrics = { path = "../common/lighthouse_metrics" } diff --git a/testing/ef_tests/Cargo.toml b/testing/ef_tests/Cargo.toml index e04d671396e..294bbe69b68 100644 --- a/testing/ef_tests/Cargo.toml +++ b/testing/ef_tests/Cargo.toml @@ -23,7 +23,7 @@ serde_derive = "1.0.116" serde_repr = "0.1.6" serde_yaml = "0.8.13" eth2_ssz = "0.4.1" -eth2_ssz_derive = "0.3.0" +eth2_ssz_derive = "0.3.1" tree_hash = "0.4.1" tree_hash_derive = "0.4.0" cached_tree_hash = { path = "../../consensus/cached_tree_hash" } From dff173a77cb7836bd369d70dbed8c2a4c688a078 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 18 Oct 2022 19:35:17 +1100 Subject: [PATCH 11/15] Fix comment --- consensus/ssz_derive/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index a0d485d8e71..e10df5df286 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -15,11 +15,11 @@ //! //! The following field attributes are available: //! -//! - `#[ssz(with = "module")]`: uses the methods in `module` to implement `ssz::Encode` or +//! - `#[ssz(with = "module")]`: uses the methods in `module` to implement `ssz::Encode` and //! `ssz::Decode`. This is useful when it's not possible to create an `impl` for that type -//! (e.g. it is defined in another crate). +//! (e.g. the type is defined in another crate). //! - `#[ssz(skip_serializing)]`: this field will not be included in the serialized SSZ vector. -//! - `#[ssz(skip_deserializing)]`: this field will not be expected to be included in the serialized +//! - `#[ssz(skip_deserializing)]`: this field will not be expected in the serialized //! SSZ vector and it will be initialized from a `Default` implementation. //! //! ## Examples @@ -215,7 +215,7 @@ impl<'a> Procedure<'a> { behaviour: EnumBehaviour::Transparent, }, Some(other) => panic!( - "{} is not a valid struct behaviour, use \"container\" or \"transparent\"", + "{} is not a valid enum behaviour, use \"container\" or \"transparent\"", other ), None => panic!("{}", NO_ENUM_BEHAVIOUR_ERROR), From e664d04b0c8225d06ffbad0b1e310ded0b1b72a5 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 14 Nov 2022 17:00:35 +1100 Subject: [PATCH 12/15] Apply suggestions from code review Co-authored-by: realbigsean --- consensus/ssz_derive/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index e10df5df286..55e3950c1c5 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -3,7 +3,7 @@ //! //! ## Attributes //! -//! The following struct\enum attributes are available: +//! The following struct/enum attributes are available: //! //! - `#[ssz(enum_behaviour = "union")]`: encodes and decodes an `enum` with a one-byte variant selector. //! - `#[ssz(enum_behaviour = "transparent")]`: allows encoding an `enum` by serializing only the @@ -763,7 +763,7 @@ fn ssz_decode_derive_struct(item: &DeriveInput, struct_data: &DataStruct) -> Tok /// Implements `ssz::Decode` "transparently" for a `struct` with exactly one non-skipped field. /// -/// The bytes will be decoded as if they are the inner field, without the outmost struct. The +/// The bytes will be decoded as if they are the inner field, without the outermost struct. The /// outermost struct will then be applied artificially. /// /// ## Field attributes From 06560b52c6cabd618e708f721e57a5eb01b68f35 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 14 Nov 2022 17:01:37 +1100 Subject: [PATCH 13/15] Remove unused variable --- consensus/ssz_derive/src/lib.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index 55e3950c1c5..0b2ad0a12e0 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -790,15 +790,10 @@ fn ssz_decode_derive_struct_transparent( ); } - let mut field_names = vec![]; let mut fields = vec![]; let mut wrapped_type = None; for (ty, ident, field_opts) in ssz_fields { - field_names.push(quote! { - #ident - }); - if field_opts.skip_deserializing { fields.push(quote! { #ident: <_>::default(), From 5e40ad106756f81bb4e4d653641cbcc6b2e47f88 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Wed, 19 Oct 2022 17:25:12 -0400 Subject: [PATCH 14/15] newtype transaparent ssz --- consensus/ssz_derive/src/lib.rs | 136 +++++++++++++++++++++------- consensus/ssz_derive/tests/tests.rs | 33 +++++++ 2 files changed, 138 insertions(+), 31 deletions(-) diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index 0b2ad0a12e0..40d63fd02fa 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -50,31 +50,55 @@ //! /// Represented as an SSZ "list" *without* an SSZ "container". //! #[derive(Encode, Decode)] //! #[ssz(struct_behaviour = "transparent")] -//! struct NewType { +//! struct WrapperStruct { //! foo: Vec //! } //! //! assert_eq!( -//! NewType { foo: vec![42] }.as_ssz_bytes(), +//! WrapperStruct { foo: vec![42] }.as_ssz_bytes(), //! vec![42] //! ); //! //! /// Represented as an SSZ "list" *without* an SSZ "container". The `bar` byte is ignored. //! #[derive(Debug, PartialEq, Encode, Decode)] //! #[ssz(struct_behaviour = "transparent")] -//! struct NewTypeSkippedField { +//! struct WrapperStructSkippedField { //! foo: Vec, //! #[ssz(skip_serializing, skip_deserializing)] //! bar: u8, //! } //! //! assert_eq!( -//! NewTypeSkippedField { foo: vec![42], bar: 99 }.as_ssz_bytes(), +//! WrapperStructSkippedField { foo: vec![42], bar: 99 }.as_ssz_bytes(), +//! vec![42] +//! ); +//! assert_eq!( +//! WrapperStructSkippedField::from_ssz_bytes(&[42]).unwrap(), +//! WrapperStructSkippedField { foo: vec![42], bar: 0 } +//! ); +//! +//! /// Represented as an SSZ "list" *without* an SSZ "container". +//! #[derive(Encode, Decode)] +//! #[ssz(struct_behaviour = "transparent")] +//! struct NewType(Vec); +//! +//! assert_eq!( +//! NewType(vec![42]).as_ssz_bytes(), +//! vec![42] +//! ); +//! +//! /// Represented as an SSZ "list" *without* an SSZ "container". The `bar` byte is ignored. +//! #[derive(Debug, PartialEq, Encode, Decode)] +//! #[ssz(struct_behaviour = "transparent")] +//! struct NewTypeSkippedField(Vec, #[ssz(skip_serializing, skip_deserializing)] u8); +//! +//! assert_eq!( +//! NewTypeSkippedField(vec![42], 99).as_ssz_bytes(), //! vec![42] //! ); //! assert_eq!( //! NewTypeSkippedField::from_ssz_bytes(&[42]).unwrap(), -//! NewTypeSkippedField { foo: vec![42], bar: 0 } +//! NewTypeSkippedField(vec![42], 0) //! ); //! ``` //! @@ -226,16 +250,15 @@ impl<'a> Procedure<'a> { } } -fn parse_ssz_fields(struct_data: &syn::DataStruct) -> Vec<(&syn::Type, &syn::Ident, FieldOpts)> { +fn parse_ssz_fields( + struct_data: &syn::DataStruct, +) -> Vec<(&syn::Type, Option<&syn::Ident>, FieldOpts)> { struct_data .fields .iter() .map(|field| { let ty = &field.ty; - let ident = match &field.ident { - Some(ref ident) => ident, - _ => panic!("ssz_derive only supports named struct fields."), - }; + let ident = field.ident.as_ref(); let field_opts_candidates = field .attrs @@ -299,6 +322,13 @@ fn ssz_encode_derive_struct(derive_input: &DeriveInput, struct_data: &DataStruct continue; } + let ident = match ident { + Some(ref ident) => ident, + _ => panic!( + "#[ssz(struct_behaviour = \"container\")] only supports named struct fields." + ), + }; + if let Some(module) = field_opts.with { let module = quote! { #module::encode }; field_is_ssz_fixed_len.push(quote! { #module::is_ssz_fixed_len() }); @@ -417,25 +447,48 @@ fn ssz_encode_derive_struct_transparent( .find(|(_, _, field_opts)| !field_opts.skip_deserializing) .expect("\"transparent\" struct must have at least one non-skipped field"); - let output = quote! { - impl #impl_generics ssz::Encode for #name #ty_generics #where_clause { - fn is_ssz_fixed_len() -> bool { - <#ty as ssz::Encode>::is_ssz_fixed_len() - } + let output = if let Some(field_name) = ident { + quote! { + impl #impl_generics ssz::Encode for #name #ty_generics #where_clause { + fn is_ssz_fixed_len() -> bool { + <#ty as ssz::Encode>::is_ssz_fixed_len() + } - fn ssz_fixed_len() -> usize { - <#ty as ssz::Encode>::ssz_fixed_len() - } + fn ssz_fixed_len() -> usize { + <#ty as ssz::Encode>::ssz_fixed_len() + } - fn ssz_bytes_len(&self) -> usize { - self.#ident.ssz_bytes_len() + fn ssz_bytes_len(&self) -> usize { + self.#field_name.ssz_bytes_len() + } + + fn ssz_append(&self, buf: &mut Vec) { + self.#field_name.ssz_append(buf) + } } + } + } else { + quote! { + impl #impl_generics ssz::Encode for #name #ty_generics #where_clause { + fn is_ssz_fixed_len() -> bool { + <#ty as ssz::Encode>::is_ssz_fixed_len() + } - fn ssz_append(&self, buf: &mut Vec) { - self.#ident.ssz_append(buf) + fn ssz_fixed_len() -> usize { + <#ty as ssz::Encode>::ssz_fixed_len() + } + + fn ssz_bytes_len(&self) -> usize { + self.0.ssz_bytes_len() + } + + fn ssz_append(&self, buf: &mut Vec) { + self.0.ssz_append(buf) + } } } }; + output.into() } @@ -625,6 +678,13 @@ fn ssz_decode_derive_struct(item: &DeriveInput, struct_data: &DataStruct) -> Tok let mut fixed_lens = vec![]; for (ty, ident, field_opts) in parse_ssz_fields(struct_data) { + let ident = match ident { + Some(ref ident) => ident, + _ => panic!( + "#[ssz(struct_behaviour = \"container\")] only supports named struct fields." + ), + }; + field_names.push(quote! { #ident }); @@ -793,16 +853,30 @@ fn ssz_decode_derive_struct_transparent( let mut fields = vec![]; let mut wrapped_type = None; - for (ty, ident, field_opts) in ssz_fields { - if field_opts.skip_deserializing { - fields.push(quote! { - #ident: <_>::default(), - }); + for (i, (ty, ident, field_opts)) in ssz_fields.into_iter().enumerate() { + if let Some(name) = ident { + if field_opts.skip_deserializing { + fields.push(quote! { + #name: <_>::default(), + }); + } else { + fields.push(quote! { + #name: <_>::from_ssz_bytes(bytes)?, + }); + wrapped_type = Some(ty); + } } else { - fields.push(quote! { - #ident: <_>::from_ssz_bytes(bytes)?, - }); - wrapped_type = Some(ty); + let index = syn::Index::from(i); + if field_opts.skip_deserializing { + fields.push(quote! { + #index:<_>::default(), + }); + } else { + fields.push(quote! { + #index:<_>::from_ssz_bytes(bytes)?, + }); + wrapped_type = Some(ty); + } } } diff --git a/consensus/ssz_derive/tests/tests.rs b/consensus/ssz_derive/tests/tests.rs index 137e491a28e..2eeb3a48db7 100644 --- a/consensus/ssz_derive/tests/tests.rs +++ b/consensus/ssz_derive/tests/tests.rs @@ -180,3 +180,36 @@ fn transparent_struct_skipped_field() { &vec![42_u8].as_ssz_bytes(), ); } + +#[derive(PartialEq, Debug, Encode, Decode)] +#[ssz(struct_behaviour = "transparent")] +struct TransparentStructNewType(Vec); + +#[test] +fn transparent_struct_newtype() { + assert_encode_decode( + &TransparentStructNewType(vec![42_u8]), + &vec![42_u8].as_ssz_bytes(), + ); +} + +#[derive(PartialEq, Debug, Encode, Decode)] +#[ssz(struct_behaviour = "transparent")] +struct TransparentStructNewTypeSkippedField( + Vec, + #[ssz(skip_serializing, skip_deserializing)] PhantomData, +); + +impl TransparentStructNewTypeSkippedField { + fn new(inner: Vec) -> Self { + Self(inner, PhantomData) + } +} + +#[test] +fn transparent_struct_newtype_skipped_field() { + assert_encode_decode( + &TransparentStructNewTypeSkippedField::new(vec![42_u8]), + &vec![42_u8].as_ssz_bytes(), + ); +} From 27a5a36bc5b01ae07716afdcc95b475e680f178c Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 14 Nov 2022 17:24:59 +1100 Subject: [PATCH 15/15] Use tuple index rather than assuming 0 --- consensus/ssz_derive/src/lib.rs | 14 +++++++++----- consensus/ssz_derive/tests/tests.rs | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/consensus/ssz_derive/src/lib.rs b/consensus/ssz_derive/src/lib.rs index 40d63fd02fa..9f8270e6dd5 100644 --- a/consensus/ssz_derive/src/lib.rs +++ b/consensus/ssz_derive/src/lib.rs @@ -147,7 +147,7 @@ use darling::{FromDeriveInput, FromMeta}; use proc_macro::TokenStream; use quote::quote; use std::convert::TryInto; -use syn::{parse_macro_input, DataEnum, DataStruct, DeriveInput, Ident}; +use syn::{parse_macro_input, DataEnum, DataStruct, DeriveInput, Ident, Index}; /// The highest possible union selector value (higher values are reserved for backwards compatible /// extensions). @@ -442,11 +442,15 @@ fn ssz_encode_derive_struct_transparent( ); } - let (ty, ident, _field_opts) = ssz_fields + let (index, (ty, ident, _field_opts)) = ssz_fields .iter() - .find(|(_, _, field_opts)| !field_opts.skip_deserializing) + .enumerate() + .find(|(_, (_, _, field_opts))| !field_opts.skip_deserializing) .expect("\"transparent\" struct must have at least one non-skipped field"); + // Remove the `_usize` suffix from the value to avoid a compiler warning. + let index = Index::from(index); + let output = if let Some(field_name) = ident { quote! { impl #impl_generics ssz::Encode for #name #ty_generics #where_clause { @@ -479,11 +483,11 @@ fn ssz_encode_derive_struct_transparent( } fn ssz_bytes_len(&self) -> usize { - self.0.ssz_bytes_len() + self.#index.ssz_bytes_len() } fn ssz_append(&self, buf: &mut Vec) { - self.0.ssz_append(buf) + self.#index.ssz_append(buf) } } } diff --git a/consensus/ssz_derive/tests/tests.rs b/consensus/ssz_derive/tests/tests.rs index 2eeb3a48db7..040d2a34761 100644 --- a/consensus/ssz_derive/tests/tests.rs +++ b/consensus/ssz_derive/tests/tests.rs @@ -213,3 +213,24 @@ fn transparent_struct_newtype_skipped_field() { &vec![42_u8].as_ssz_bytes(), ); } + +#[derive(PartialEq, Debug, Encode, Decode)] +#[ssz(struct_behaviour = "transparent")] +struct TransparentStructNewTypeSkippedFieldReverse( + #[ssz(skip_serializing, skip_deserializing)] PhantomData, + Vec, +); + +impl TransparentStructNewTypeSkippedFieldReverse { + fn new(inner: Vec) -> Self { + Self(PhantomData, inner) + } +} + +#[test] +fn transparent_struct_newtype_skipped_field_reverse() { + assert_encode_decode( + &TransparentStructNewTypeSkippedFieldReverse::new(vec![42_u8]), + &vec![42_u8].as_ssz_bytes(), + ); +}