From 580257755501a2312d22d3c105df09d6c2150dd4 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 6 Oct 2023 15:36:56 -0600 Subject: [PATCH 1/7] add mainnet preset for polymorphic types --- ethereum-consensus/src/types/mod.rs | 1 + .../src/types/presets/mainnet.rs | 134 ++++++++++++++++++ ethereum-consensus/src/types/presets/mod.rs | 1 + 3 files changed, 136 insertions(+) create mode 100644 ethereum-consensus/src/types/presets/mainnet.rs create mode 100644 ethereum-consensus/src/types/presets/mod.rs diff --git a/ethereum-consensus/src/types/mod.rs b/ethereum-consensus/src/types/mod.rs index db004817a..cc363b4d7 100644 --- a/ethereum-consensus/src/types/mod.rs +++ b/ethereum-consensus/src/types/mod.rs @@ -11,6 +11,7 @@ mod blinded_beacon_block; mod blinded_beacon_block_body; mod execution_payload; mod execution_payload_header; +pub mod presets; mod signed_beacon_block; mod signed_blinded_beacon_block; diff --git a/ethereum-consensus/src/types/presets/mainnet.rs b/ethereum-consensus/src/types/presets/mainnet.rs new file mode 100644 index 000000000..360db6659 --- /dev/null +++ b/ethereum-consensus/src/types/presets/mainnet.rs @@ -0,0 +1,134 @@ +use crate::{ + altair::mainnet::SYNC_COMMITTEE_SIZE, + bellatrix::mainnet::{ + BYTES_PER_LOGS_BLOOM, MAX_BYTES_PER_TRANSACTION, MAX_EXTRA_DATA_BYTES, + MAX_TRANSACTIONS_PER_PAYLOAD, + }, + capella::mainnet::{MAX_BLS_TO_EXECUTION_CHANGES, MAX_WITHDRAWALS_PER_PAYLOAD}, + deneb::mainnet::MAX_BLOB_COMMITMENTS_PER_BLOCK, + phase0::mainnet::{ + EPOCHS_PER_HISTORICAL_VECTOR, EPOCHS_PER_SLASHINGS_VECTOR, ETH1_DATA_VOTES_BOUND, + HISTORICAL_ROOTS_LIMIT, MAX_ATTESTATIONS, MAX_ATTESTER_SLASHINGS, MAX_DEPOSITS, + MAX_PROPOSER_SLASHINGS, MAX_VALIDATORS_PER_COMMITTEE, MAX_VOLUNTARY_EXITS, + PENDING_ATTESTATIONS_BOUND, SLOTS_PER_HISTORICAL_ROOT, VALIDATOR_REGISTRY_LIMIT, + }, + types, +}; + +pub type BeaconBlockBody = types::BeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type BeaconBlock = types::BeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type SignedBeaconBlock = types::SignedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type BlindedBeaconBlockBody = types::BlindedBeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type BlindedBeaconBlock = types::BlindedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type SignedBlindedBeaconBlock = types::SignedBlindedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type ExecutionPayload = types::ExecutionPayload< + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, +>; + +pub type ExecutionPayloadHeader = + types::ExecutionPayloadHeader; + +pub type BeaconState = types::BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + PENDING_ATTESTATIONS_BOUND, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, +>; diff --git a/ethereum-consensus/src/types/presets/mod.rs b/ethereum-consensus/src/types/presets/mod.rs new file mode 100644 index 000000000..c7dabf9d7 --- /dev/null +++ b/ethereum-consensus/src/types/presets/mod.rs @@ -0,0 +1 @@ +pub mod mainnet; From f81e749bed6776b150ee40d076d76247e5643e9c Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 6 Oct 2023 15:42:59 -0600 Subject: [PATCH 2/7] add serde tagging attribute to all polymorphic types --- ethereum-consensus/src/types/beacon_block.rs | 5 +++-- ethereum-consensus/src/types/beacon_block_body.rs | 5 +++-- ethereum-consensus/src/types/beacon_state.rs | 5 +++-- ethereum-consensus/src/types/blinded_beacon_block.rs | 5 +++-- ethereum-consensus/src/types/blinded_beacon_block_body.rs | 5 +++-- ethereum-consensus/src/types/execution_payload.rs | 5 +++-- ethereum-consensus/src/types/execution_payload_header.rs | 5 +++-- ethereum-consensus/src/types/signed_beacon_block.rs | 5 +++-- ethereum-consensus/src/types/signed_blinded_beacon_block.rs | 5 +++-- spec-gen/src/type_generator.rs | 5 +++-- 10 files changed, 30 insertions(+), 20 deletions(-) diff --git a/ethereum-consensus/src/types/beacon_block.rs b/ethereum-consensus/src/types/beacon_block.rs index 64dc79ada..3ae3edc3f 100644 --- a/ethereum-consensus/src/types/beacon_block.rs +++ b/ethereum-consensus/src/types/beacon_block.rs @@ -9,8 +9,9 @@ use crate::{ ssz::prelude::*, types::beacon_block_body::{BeaconBlockBodyRef, BeaconBlockBodyRefMut}, }; -#[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[serde(tag = "version", content = "data")] +#[serde(rename_all = "lowercase")] pub enum BeaconBlock< const MAX_PROPOSER_SLASHINGS: usize, const MAX_VALIDATORS_PER_COMMITTEE: usize, diff --git a/ethereum-consensus/src/types/beacon_block_body.rs b/ethereum-consensus/src/types/beacon_block_body.rs index cb6bb48db..3dabb5ca2 100644 --- a/ethereum-consensus/src/types/beacon_block_body.rs +++ b/ethereum-consensus/src/types/beacon_block_body.rs @@ -13,8 +13,9 @@ use crate::{ ssz::prelude::*, types::execution_payload::{ExecutionPayloadRef, ExecutionPayloadRefMut}, }; -#[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[serde(tag = "version", content = "data")] +#[serde(rename_all = "lowercase")] pub enum BeaconBlockBody< const MAX_PROPOSER_SLASHINGS: usize, const MAX_VALIDATORS_PER_COMMITTEE: usize, diff --git a/ethereum-consensus/src/types/beacon_state.rs b/ethereum-consensus/src/types/beacon_state.rs index 64d0f07df..9a6883bb4 100644 --- a/ethereum-consensus/src/types/beacon_state.rs +++ b/ethereum-consensus/src/types/beacon_state.rs @@ -15,8 +15,9 @@ use crate::{ ssz::prelude::*, types::execution_payload_header::{ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut}, }; -#[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[serde(tag = "version", content = "data")] +#[serde(rename_all = "lowercase")] pub enum BeaconState< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, diff --git a/ethereum-consensus/src/types/blinded_beacon_block.rs b/ethereum-consensus/src/types/blinded_beacon_block.rs index b3bd34977..ba5eaf4bf 100644 --- a/ethereum-consensus/src/types/blinded_beacon_block.rs +++ b/ethereum-consensus/src/types/blinded_beacon_block.rs @@ -7,8 +7,9 @@ use crate::{ ssz::prelude::*, types::blinded_beacon_block_body::{BlindedBeaconBlockBodyRef, BlindedBeaconBlockBodyRefMut}, }; -#[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[serde(tag = "version", content = "data")] +#[serde(rename_all = "lowercase")] pub enum BlindedBeaconBlock< const MAX_PROPOSER_SLASHINGS: usize, const MAX_VALIDATORS_PER_COMMITTEE: usize, diff --git a/ethereum-consensus/src/types/blinded_beacon_block_body.rs b/ethereum-consensus/src/types/blinded_beacon_block_body.rs index dc354dfa5..ce323e969 100644 --- a/ethereum-consensus/src/types/blinded_beacon_block_body.rs +++ b/ethereum-consensus/src/types/blinded_beacon_block_body.rs @@ -12,8 +12,9 @@ use crate::{ ssz::prelude::*, types::execution_payload_header::{ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut}, }; -#[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[serde(tag = "version", content = "data")] +#[serde(rename_all = "lowercase")] pub enum BlindedBeaconBlockBody< const MAX_PROPOSER_SLASHINGS: usize, const MAX_VALIDATORS_PER_COMMITTEE: usize, diff --git a/ethereum-consensus/src/types/execution_payload.rs b/ethereum-consensus/src/types/execution_payload.rs index 696d55b4c..5835423cd 100644 --- a/ethereum-consensus/src/types/execution_payload.rs +++ b/ethereum-consensus/src/types/execution_payload.rs @@ -6,8 +6,9 @@ use crate::{ primitives::{Bytes32, ExecutionAddress, Hash32}, ssz::prelude::*, }; -#[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[serde(tag = "version", content = "data")] +#[serde(rename_all = "lowercase")] pub enum ExecutionPayload< const BYTES_PER_LOGS_BLOOM: usize, const MAX_EXTRA_DATA_BYTES: usize, diff --git a/ethereum-consensus/src/types/execution_payload_header.rs b/ethereum-consensus/src/types/execution_payload_header.rs index c93c4a355..2bf8c4583 100644 --- a/ethereum-consensus/src/types/execution_payload_header.rs +++ b/ethereum-consensus/src/types/execution_payload_header.rs @@ -6,8 +6,9 @@ use crate::{ primitives::{Bytes32, ExecutionAddress, Hash32, Root}, ssz::prelude::*, }; -#[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[serde(tag = "version", content = "data")] +#[serde(rename_all = "lowercase")] pub enum ExecutionPayloadHeader< const BYTES_PER_LOGS_BLOOM: usize, const MAX_EXTRA_DATA_BYTES: usize, diff --git a/ethereum-consensus/src/types/signed_beacon_block.rs b/ethereum-consensus/src/types/signed_beacon_block.rs index 2c6140e62..ba593d4e8 100644 --- a/ethereum-consensus/src/types/signed_beacon_block.rs +++ b/ethereum-consensus/src/types/signed_beacon_block.rs @@ -9,8 +9,9 @@ use crate::{ ssz::prelude::*, types::beacon_block::{BeaconBlockRef, BeaconBlockRefMut}, }; -#[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[serde(tag = "version", content = "data")] +#[serde(rename_all = "lowercase")] pub enum SignedBeaconBlock< const MAX_PROPOSER_SLASHINGS: usize, const MAX_VALIDATORS_PER_COMMITTEE: usize, diff --git a/ethereum-consensus/src/types/signed_blinded_beacon_block.rs b/ethereum-consensus/src/types/signed_blinded_beacon_block.rs index a22ff2e35..b8a08fe34 100644 --- a/ethereum-consensus/src/types/signed_blinded_beacon_block.rs +++ b/ethereum-consensus/src/types/signed_blinded_beacon_block.rs @@ -7,8 +7,9 @@ use crate::{ ssz::prelude::*, types::blinded_beacon_block::{BlindedBeaconBlockRef, BlindedBeaconBlockRefMut}, }; -#[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[serde(tag = "version", content = "data")] +#[serde(rename_all = "lowercase")] pub enum SignedBlindedBeaconBlock< const MAX_PROPOSER_SLASHINGS: usize, const MAX_VALIDATORS_PER_COMMITTEE: usize, diff --git a/spec-gen/src/type_generator.rs b/spec-gen/src/type_generator.rs index aec033abb..c9620caf1 100644 --- a/spec-gen/src/type_generator.rs +++ b/spec-gen/src/type_generator.rs @@ -356,8 +356,9 @@ fn derive_type_defn(target_type: &Type, merge_type: &MergeType) -> (Item, Generi }) .collect::>(); let enum_defn = parse_quote! { - #[derive(Debug, SimpleSerialize, Clone, PartialEq, Eq)] - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + #[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] + #[serde(tag = "version", content = "data")] + #[serde(rename_all = "lowercase")] pub enum #type_name #generics { #(#variant_defns),* } From 9b32fc691c1ea60d95bcc228b7bf0ead9eaa1af8 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 6 Oct 2023 17:57:18 -0600 Subject: [PATCH 3/7] implement serde for VersionedValue --- beacon-api-client/src/types.rs | 160 +++++++++++++++--- .../src/state_transition/context.rs | 3 +- 2 files changed, 140 insertions(+), 23 deletions(-) diff --git a/beacon-api-client/src/types.rs b/beacon-api-client/src/types.rs index 02fc3b7ad..ae08a99c7 100644 --- a/beacon-api-client/src/types.rs +++ b/beacon-api-client/src/types.rs @@ -8,9 +8,10 @@ use ethereum_consensus::{ Root, Slot, ValidatorIndex, Version, }, serde::try_bytes_from_hex_str, + state_transition::Forks, }; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use std::{collections::HashMap, fmt, str::FromStr}; +use serde::{ser::SerializeMap, Deserialize, Serialize}; +use std::{collections::HashMap, fmt, marker::PhantomData, str::FromStr}; #[derive(Serialize, Deserialize)] pub struct VersionData { @@ -457,38 +458,153 @@ pub struct ValidatorLiveness { } #[derive(Serialize, Deserialize, Debug)] -#[serde(bound = "T: Serialize + serde::de::DeserializeOwned")] -pub struct Value { +#[serde(bound = "T: serde::Serialize + serde::de::DeserializeOwned")] +pub struct Value { pub data: T, #[serde(flatten)] pub meta: HashMap, } -/* -`VersionedValue` captures: -```json -{ - "version": "fork-version", - "data": { ... }, - < optional additional metadata >, -} - -And can be combined with Rust `enum`s to handle polymorphic {de,}serialization. -``` - */ -#[derive(serde::Serialize, serde::Deserialize, Debug)] -#[serde(bound = "T: serde::Serialize + serde::de::DeserializeOwned")] +#[derive(Debug)] pub struct VersionedValue { - #[serde(flatten)] - pub payload: T, - #[serde(flatten)] + pub version: Forks, + pub data: T, pub meta: HashMap, } +impl serde::Serialize for VersionedValue { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let count = 2 + self.meta.len(); + let mut versioned_value = serializer.serialize_map(Some(count))?; + let inner = serde_json::to_value(&self.data).map_err(serde::ser::Error::custom)?; + versioned_value.serialize_entry("version", inner.get("version").unwrap())?; + versioned_value.serialize_entry("data", inner.get("data").unwrap())?; + for (name, value) in &self.meta { + versioned_value.serialize_entry(name, value)?; + } + versioned_value.end() + } +} + +impl<'de, T: serde::Serialize + serde::de::DeserializeOwned> serde::Deserialize<'de> + for VersionedValue +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Debug)] + enum Field<'de> { + Version, + Data, + Meta(&'de str), + } + + impl<'de> serde::Deserialize<'de> for Field<'de> { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> serde::de::Visitor<'de> for FieldVisitor { + type Value = Field<'de>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("some field name") + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: serde::de::Error, + { + match v { + "version" => Ok(Field::Version), + "data" => Ok(Field::Data), + s => Ok(Field::Meta(s)), + } + } + } + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct Visitor(PhantomData); + + impl<'de, T: serde::Serialize + serde::de::DeserializeOwned> serde::de::Visitor<'de> + for Visitor + { + type Value = VersionedValue; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct VersionedValue") + } + + fn visit_map(self, mut map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let mut version = None; + let mut version_str = None; + let mut data: Option = None; + let mut meta = HashMap::default(); + while let Some(key) = map.next_key()? { + match key { + Field::Version => { + if version.is_some() { + return Err(serde::de::Error::duplicate_field("version")) + } + let version_value: serde_json::Value = map.next_value()?; + let fork: Forks = serde_json::from_value(version_value.clone()) + .map_err(serde::de::Error::custom)?; + version = Some(fork); + match version_value { + serde_json::Value::String(inner) => { + version_str = Some(inner); + } + other => { + return Err(serde::de::Error::custom(format!( + "expected JSON string, but found value {other}" + ))) + } + }; + } + Field::Data => { + if data.is_some() { + return Err(serde::de::Error::duplicate_field("data")) + } + data = Some(map.next_value()?); + } + Field::Meta(name) => { + let next_value: serde_json::Value = map.next_value()?; + meta.insert(name.to_string(), next_value); + } + } + } + let version = version.ok_or_else(|| serde::de::Error::missing_field("version"))?; + let data = data.ok_or_else(|| serde::de::Error::missing_field("data"))?; + let data_with_version = serde_json::json!({ + "version": version_str, + "data": data, + }); + let data: T = + serde_json::from_value(data_with_version).map_err(serde::de::Error::custom)?; + Ok(VersionedValue { version, data, meta }) + } + } + + const FIELDS: &[&str] = &["version", "data", "meta"]; + deserializer.deserialize_struct("VersionedValue", FIELDS, Visitor(PhantomData)) + } +} + #[derive(Serialize, Deserialize, Debug)] #[serde(bound = "T: Serialize + serde::de::DeserializeOwned")] #[serde(untagged)] -pub enum ApiResult { +pub enum ApiResult { Ok(T), Err(ApiError), } diff --git a/ethereum-consensus/src/state_transition/context.rs b/ethereum-consensus/src/state_transition/context.rs index 13f259798..3e4cda7c4 100644 --- a/ethereum-consensus/src/state_transition/context.rs +++ b/ethereum-consensus/src/state_transition/context.rs @@ -9,7 +9,8 @@ use crate::{ state_transition::Error, }; -#[derive(Debug)] +#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "lowercase")] pub enum Forks { Phase0, Altair, From 4744ba59ccfcbc6ac9b8149b823f6e372c5c9ce4 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 6 Oct 2023 18:25:51 -0600 Subject: [PATCH 4/7] reorg types presets --- ethereum-consensus/src/types/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethereum-consensus/src/types/mod.rs b/ethereum-consensus/src/types/mod.rs index cc363b4d7..b07343b32 100644 --- a/ethereum-consensus/src/types/mod.rs +++ b/ethereum-consensus/src/types/mod.rs @@ -11,7 +11,7 @@ mod blinded_beacon_block; mod blinded_beacon_block_body; mod execution_payload; mod execution_payload_header; -pub mod presets; +mod presets; mod signed_beacon_block; mod signed_blinded_beacon_block; @@ -24,3 +24,5 @@ pub use execution_payload::*; pub use execution_payload_header::*; pub use signed_beacon_block::*; pub use signed_blinded_beacon_block::*; + +pub use presets::mainnet; From e97a79b36bdcb04b5ab133fbe5f5b68f350dac74 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 6 Oct 2023 18:26:41 -0600 Subject: [PATCH 5/7] add minimal preset for polymorphic types --- ethereum-consensus/src/types/mod.rs | 2 +- .../src/types/presets/minimal.rs | 134 ++++++++++++++++++ ethereum-consensus/src/types/presets/mod.rs | 1 + 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 ethereum-consensus/src/types/presets/minimal.rs diff --git a/ethereum-consensus/src/types/mod.rs b/ethereum-consensus/src/types/mod.rs index b07343b32..66d47bf3c 100644 --- a/ethereum-consensus/src/types/mod.rs +++ b/ethereum-consensus/src/types/mod.rs @@ -25,4 +25,4 @@ pub use execution_payload_header::*; pub use signed_beacon_block::*; pub use signed_blinded_beacon_block::*; -pub use presets::mainnet; +pub use presets::{mainnet, minimal}; diff --git a/ethereum-consensus/src/types/presets/minimal.rs b/ethereum-consensus/src/types/presets/minimal.rs new file mode 100644 index 000000000..79d376807 --- /dev/null +++ b/ethereum-consensus/src/types/presets/minimal.rs @@ -0,0 +1,134 @@ +use crate::{ + altair::minimal::SYNC_COMMITTEE_SIZE, + bellatrix::minimal::{ + BYTES_PER_LOGS_BLOOM, MAX_BYTES_PER_TRANSACTION, MAX_EXTRA_DATA_BYTES, + MAX_TRANSACTIONS_PER_PAYLOAD, + }, + capella::minimal::{MAX_BLS_TO_EXECUTION_CHANGES, MAX_WITHDRAWALS_PER_PAYLOAD}, + deneb::minimal::MAX_BLOB_COMMITMENTS_PER_BLOCK, + phase0::minimal::{ + EPOCHS_PER_HISTORICAL_VECTOR, EPOCHS_PER_SLASHINGS_VECTOR, ETH1_DATA_VOTES_BOUND, + HISTORICAL_ROOTS_LIMIT, MAX_ATTESTATIONS, MAX_ATTESTER_SLASHINGS, MAX_DEPOSITS, + MAX_PROPOSER_SLASHINGS, MAX_VALIDATORS_PER_COMMITTEE, MAX_VOLUNTARY_EXITS, + PENDING_ATTESTATIONS_BOUND, SLOTS_PER_HISTORICAL_ROOT, VALIDATOR_REGISTRY_LIMIT, + }, + types, +}; + +pub type BeaconBlockBody = types::BeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type BeaconBlock = types::BeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type SignedBeaconBlock = types::SignedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type BlindedBeaconBlockBody = types::BlindedBeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type BlindedBeaconBlock = types::BlindedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type SignedBlindedBeaconBlock = types::SignedBlindedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, +>; + +pub type ExecutionPayload = types::ExecutionPayload< + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, +>; + +pub type ExecutionPayloadHeader = + types::ExecutionPayloadHeader; + +pub type BeaconState = types::BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + PENDING_ATTESTATIONS_BOUND, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, +>; diff --git a/ethereum-consensus/src/types/presets/mod.rs b/ethereum-consensus/src/types/presets/mod.rs index c7dabf9d7..f9578b40a 100644 --- a/ethereum-consensus/src/types/presets/mod.rs +++ b/ethereum-consensus/src/types/presets/mod.rs @@ -1 +1,2 @@ pub mod mainnet; +pub mod minimal; From 1d226e8aafe04e24e620d6dde31ded456fc5f5c9 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 6 Oct 2023 18:42:14 -0600 Subject: [PATCH 6/7] install new polymorphic types --- beacon-api-client/examples/api_sketch.rs | 15 ++++------- beacon-api-client/src/api_client.rs | 12 ++++----- beacon-api-client/src/lib.rs | 34 +++++++++++++++--------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/beacon-api-client/examples/api_sketch.rs b/beacon-api-client/examples/api_sketch.rs index 4a0f8b654..d55e88e8f 100644 --- a/beacon-api-client/examples/api_sketch.rs +++ b/beacon-api-client/examples/api_sketch.rs @@ -1,15 +1,9 @@ use beacon_api_client::{ApiError, ApiResult, Value, VersionedValue}; -use ethereum_consensus::{bellatrix::mainnet as bellatrix, capella::mainnet as capella}; +use ethereum_consensus::{ + bellatrix::mainnet as bellatrix, state_transition::Forks, types::mainnet::BlindedBeaconBlock, +}; use std::collections::HashMap; -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "version", content = "data")] -#[serde(rename_all = "lowercase")] -enum BlindedBeaconBlock { - Bellatrix(bellatrix::BlindedBeaconBlock), - Capella(capella::BlindedBeaconBlock), -} - fn main() { let block = Value { meta: HashMap::new(), data: bellatrix::BlindedBeaconBlock::default() }; let block_repr = serde_json::to_string(&block).unwrap(); @@ -43,7 +37,8 @@ fn main() { println!("{recovered_success:#?}"); let full_success_response = ApiResult::Ok(VersionedValue { - payload: block, + version: Forks::Capella, + data: block, meta: HashMap::from_iter([( String::from("finalized_root"), serde_json::Value::String("0xdeadbeefcafe".to_string()), diff --git a/beacon-api-client/src/api_client.rs b/beacon-api-client/src/api_client.rs index a05e38518..36e02ec38 100644 --- a/beacon-api-client/src/api_client.rs +++ b/beacon-api-client/src/api_client.rs @@ -7,7 +7,7 @@ use crate::{ HealthStatus, NetworkIdentity, PeerDescription, PeerState, PeerSummary, ProposerDuty, PublicKeyOrIndex, RootData, StateId, SyncCommitteeDescriptor, SyncCommitteeDuty, SyncCommitteeSummary, SyncStatus, ValidatorLiveness, ValidatorStatus, ValidatorSummary, - Value, VersionData, + Value, VersionData, VersionedValue, }, ApiError, Error, }; @@ -370,7 +370,7 @@ impl< // v2 endpoint pub async fn get_beacon_block(&self, id: BlockId) -> Result { - let result: Value = + let result: VersionedValue = self.get(&format!("eth/v2/beacon/blocks/{id}")).await?; Ok(result.data) } @@ -414,7 +414,7 @@ impl< } pub async fn get_blinded_block(&self, id: BlockId) -> Result { - let result: Value = + let result: VersionedValue = self.get(&format!("eth/v1/beacon/blinded_blocks/{id}")).await?; Ok(result.data) } @@ -586,7 +586,7 @@ impl< /* debug namespace */ // v2 endpoint pub async fn get_state(&self, id: StateId) -> Result { - let result: Value = + let result: VersionedValue = self.get(&format!("eth/v2/debug/beacon/states/{id}")).await?; Ok(result.data) } @@ -724,7 +724,7 @@ impl< request = request.query(&[("graffiti", graffiti)]); } let response = request.send().await?; - let result: ApiResult> = response.json().await?; + let result: ApiResult> = response.json().await?; match result { ApiResult::Ok(result) => Ok(result.data), ApiResult::Err(err) => Err(err.into()), @@ -745,7 +745,7 @@ impl< request = request.query(&[("graffiti", graffiti)]); } let response = request.send().await?; - let result: ApiResult> = response.json().await?; + let result: ApiResult> = response.json().await?; match result { ApiResult::Ok(result) => Ok(result.data), ApiResult::Err(err) => Err(err.into()), diff --git a/beacon-api-client/src/lib.rs b/beacon-api-client/src/lib.rs index 11b7c3bbc..980bb1ad3 100644 --- a/beacon-api-client/src/lib.rs +++ b/beacon-api-client/src/lib.rs @@ -34,21 +34,26 @@ mod error { pub mod presets { pub mod mainnet { use ethereum_consensus::{ - altair::mainnet as altair, bellatrix::mainnet as bellatrix, deneb::mainnet as deneb, + altair::mainnet as altair, + deneb::mainnet as deneb, phase0::mainnet as phase0, + types::mainnet::{ + BeaconBlock, BeaconState, BlindedBeaconBlock, SignedBeaconBlock, + SignedBlindedBeaconBlock, + }, }; pub type Client = crate::Client< altair::SignedContributionAndProof, altair::SyncCommitteeContribution, - bellatrix::BlindedBeaconBlock, - bellatrix::SignedBlindedBeaconBlock, + BlindedBeaconBlock, + SignedBlindedBeaconBlock, phase0::Attestation, phase0::AttesterSlashing, - phase0::BeaconBlock, - phase0::BeaconState, + BeaconBlock, + BeaconState, phase0::SignedAggregateAndProof, - phase0::SignedBeaconBlock, + SignedBeaconBlock, deneb::BlobSidecar, altair::LightClientBootstrap, altair::LightClientUpdate, @@ -58,21 +63,26 @@ pub mod presets { } pub mod minimal { use ethereum_consensus::{ - altair::minimal as altair, bellatrix::minimal as bellatrix, deneb::minimal as deneb, + altair::minimal as altair, + deneb::minimal as deneb, phase0::minimal as phase0, + types::minimal::{ + BeaconBlock, BeaconState, BlindedBeaconBlock, SignedBeaconBlock, + SignedBlindedBeaconBlock, + }, }; pub type Client = crate::Client< altair::SignedContributionAndProof, altair::SyncCommitteeContribution, - bellatrix::BlindedBeaconBlock, - bellatrix::SignedBlindedBeaconBlock, + BlindedBeaconBlock, + SignedBlindedBeaconBlock, phase0::Attestation, phase0::AttesterSlashing, - phase0::BeaconBlock, - phase0::BeaconState, + BeaconBlock, + BeaconState, phase0::SignedAggregateAndProof, - phase0::SignedBeaconBlock, + SignedBeaconBlock, deneb::BlobSidecar, altair::LightClientBootstrap, altair::LightClientUpdate, From 22ebbab3480d059069bac3ca176fc7a8f3f876af Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Mon, 9 Oct 2023 16:03:07 -0600 Subject: [PATCH 7/7] implement custom serialization for polymorphic types to match beacon-apis --- beacon-api-client/examples/api_sketch.rs | 18 +++++-- beacon-api-client/src/types.rs | 21 +------- ethereum-consensus/src/types/beacon_block.rs | 48 ++++++++++++++++++- .../src/types/beacon_block_body.rs | 48 ++++++++++++++++++- ethereum-consensus/src/types/beacon_state.rs | 42 +++++++++++++++- .../src/types/blinded_beacon_block.rs | 40 +++++++++++++++- .../src/types/blinded_beacon_block_body.rs | 40 +++++++++++++++- .../src/types/execution_payload.rs | 28 ++++++++++- .../src/types/execution_payload_header.rs | 16 ++++++- .../src/types/signed_beacon_block.rs | 48 ++++++++++++++++++- .../src/types/signed_blinded_beacon_block.rs | 40 +++++++++++++++- spec-gen/src/type_generator.rs | 43 +++++++++++++---- 12 files changed, 392 insertions(+), 40 deletions(-) diff --git a/beacon-api-client/examples/api_sketch.rs b/beacon-api-client/examples/api_sketch.rs index d55e88e8f..9a14cb59e 100644 --- a/beacon-api-client/examples/api_sketch.rs +++ b/beacon-api-client/examples/api_sketch.rs @@ -4,6 +4,13 @@ use ethereum_consensus::{ }; use std::collections::HashMap; +fn with_fork(fork: Forks, value: T) -> serde_json::Value { + serde_json::json!( { + "version": fork, + "data": value, + }) +} + fn main() { let block = Value { meta: HashMap::new(), data: bellatrix::BlindedBeaconBlock::default() }; let block_repr = serde_json::to_string(&block).unwrap(); @@ -18,9 +25,10 @@ fn main() { println!("{block_with_version_repr}"); let block = BlindedBeaconBlock::Bellatrix(Default::default()); - let block_with_version_repr = serde_json::to_string(&block).unwrap(); + let block_with_version_repr = + serde_json::to_string(&with_fork(Forks::Bellatrix, &block)).unwrap(); println!("{block_with_version_repr}"); - let recovered_block: BlindedBeaconBlock = + let recovered_block: VersionedValue = serde_json::from_str(&block_with_version_repr).unwrap(); println!("{recovered_block:#?}"); @@ -28,7 +36,11 @@ fn main() { let block_with_version_repr = serde_json::to_string(&block).unwrap(); println!("{block_with_version_repr}"); - let full_success_response = ApiResult::Ok(block.clone()); + let full_success_response = ApiResult::Ok(VersionedValue { + version: Forks::Capella, + data: block.clone(), + meta: Default::default(), + }); let str_repr = serde_json::to_string(&full_success_response).unwrap(); println!("{str_repr}"); diff --git a/beacon-api-client/src/types.rs b/beacon-api-client/src/types.rs index ae08a99c7..e2432c871 100644 --- a/beacon-api-client/src/types.rs +++ b/beacon-api-client/src/types.rs @@ -10,7 +10,7 @@ use ethereum_consensus::{ serde::try_bytes_from_hex_str, state_transition::Forks, }; -use serde::{ser::SerializeMap, Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fmt, marker::PhantomData, str::FromStr}; #[derive(Serialize, Deserialize)] @@ -465,30 +465,13 @@ pub struct Value { pub meta: HashMap, } -#[derive(Debug)] +#[derive(Debug, Serialize)] pub struct VersionedValue { pub version: Forks, pub data: T, pub meta: HashMap, } -impl serde::Serialize for VersionedValue { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let count = 2 + self.meta.len(); - let mut versioned_value = serializer.serialize_map(Some(count))?; - let inner = serde_json::to_value(&self.data).map_err(serde::ser::Error::custom)?; - versioned_value.serialize_entry("version", inner.get("version").unwrap())?; - versioned_value.serialize_entry("data", inner.get("data").unwrap())?; - for (name, value) in &self.meta { - versioned_value.serialize_entry(name, value)?; - } - versioned_value.end() - } -} - impl<'de, T: serde::Serialize + serde::de::DeserializeOwned> serde::Deserialize<'de> for VersionedValue { diff --git a/ethereum-consensus/src/types/beacon_block.rs b/ethereum-consensus/src/types/beacon_block.rs index 3ae3edc3f..30ab3bd8c 100644 --- a/ethereum-consensus/src/types/beacon_block.rs +++ b/ethereum-consensus/src/types/beacon_block.rs @@ -9,7 +9,7 @@ use crate::{ ssz::prelude::*, types::beacon_block_body::{BeaconBlockBodyRef, BeaconBlockBodyRefMut}, }; -#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum BeaconBlock< @@ -470,6 +470,52 @@ impl< } } } +impl< + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + > serde::Serialize + for BeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + > +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Phase0(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Altair(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Bellatrix(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Capella(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Deneb(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + } + } +} #[derive(Debug, PartialEq, Eq)] pub enum BeaconBlockRef< 'a, diff --git a/ethereum-consensus/src/types/beacon_block_body.rs b/ethereum-consensus/src/types/beacon_block_body.rs index 3dabb5ca2..51341c465 100644 --- a/ethereum-consensus/src/types/beacon_block_body.rs +++ b/ethereum-consensus/src/types/beacon_block_body.rs @@ -13,7 +13,7 @@ use crate::{ ssz::prelude::*, types::execution_payload::{ExecutionPayloadRef, ExecutionPayloadRefMut}, }; -#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum BeaconBlockBody< @@ -604,6 +604,52 @@ impl< } } } +impl< + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + > serde::Serialize + for BeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + > +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Phase0(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Altair(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Bellatrix(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Capella(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Deneb(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + } + } +} #[derive(Debug, PartialEq, Eq)] pub enum BeaconBlockBodyRef< 'a, diff --git a/ethereum-consensus/src/types/beacon_state.rs b/ethereum-consensus/src/types/beacon_state.rs index 9a6883bb4..34275bd77 100644 --- a/ethereum-consensus/src/types/beacon_state.rs +++ b/ethereum-consensus/src/types/beacon_state.rs @@ -15,7 +15,7 @@ use crate::{ ssz::prelude::*, types::execution_payload_header::{ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut}, }; -#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum BeaconState< @@ -898,6 +898,46 @@ impl< } } } +impl< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const PENDING_ATTESTATIONS_BOUND: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + > serde::Serialize + for BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + PENDING_ATTESTATIONS_BOUND, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + > +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Phase0(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Altair(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Bellatrix(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Capella(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Deneb(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + } + } +} #[derive(Debug, PartialEq, Eq)] pub enum BeaconStateRef< 'a, diff --git a/ethereum-consensus/src/types/blinded_beacon_block.rs b/ethereum-consensus/src/types/blinded_beacon_block.rs index ba5eaf4bf..7a205332e 100644 --- a/ethereum-consensus/src/types/blinded_beacon_block.rs +++ b/ethereum-consensus/src/types/blinded_beacon_block.rs @@ -7,7 +7,7 @@ use crate::{ ssz::prelude::*, types::blinded_beacon_block_body::{BlindedBeaconBlockBodyRef, BlindedBeaconBlockBodyRefMut}, }; -#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum BlindedBeaconBlock< @@ -322,6 +322,44 @@ impl< } } } +impl< + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + > serde::Serialize + for BlindedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + > +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Bellatrix(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Capella(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Deneb(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + } + } +} #[derive(Debug, PartialEq, Eq)] pub enum BlindedBeaconBlockRef< 'a, diff --git a/ethereum-consensus/src/types/blinded_beacon_block_body.rs b/ethereum-consensus/src/types/blinded_beacon_block_body.rs index ce323e969..ed8292fce 100644 --- a/ethereum-consensus/src/types/blinded_beacon_block_body.rs +++ b/ethereum-consensus/src/types/blinded_beacon_block_body.rs @@ -12,7 +12,7 @@ use crate::{ ssz::prelude::*, types::execution_payload_header::{ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut}, }; -#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum BlindedBeaconBlockBody< @@ -418,6 +418,44 @@ impl< } } } +impl< + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + > serde::Serialize + for BlindedBeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + > +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Bellatrix(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Capella(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Deneb(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + } + } +} #[derive(Debug, PartialEq, Eq)] pub enum BlindedBeaconBlockBodyRef< 'a, diff --git a/ethereum-consensus/src/types/execution_payload.rs b/ethereum-consensus/src/types/execution_payload.rs index 5835423cd..aa6f3cd5b 100644 --- a/ethereum-consensus/src/types/execution_payload.rs +++ b/ethereum-consensus/src/types/execution_payload.rs @@ -6,7 +6,7 @@ use crate::{ primitives::{Bytes32, ExecutionAddress, Hash32}, ssz::prelude::*, }; -#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum ExecutionPayload< @@ -398,6 +398,32 @@ impl< } } } +impl< + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + > serde::Serialize + for ExecutionPayload< + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + > +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Bellatrix(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Capella(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Deneb(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + } + } +} #[derive(Debug, PartialEq, Eq)] pub enum ExecutionPayloadRef< 'a, diff --git a/ethereum-consensus/src/types/execution_payload_header.rs b/ethereum-consensus/src/types/execution_payload_header.rs index 2bf8c4583..3da161089 100644 --- a/ethereum-consensus/src/types/execution_payload_header.rs +++ b/ethereum-consensus/src/types/execution_payload_header.rs @@ -6,7 +6,7 @@ use crate::{ primitives::{Bytes32, ExecutionAddress, Hash32, Root}, ssz::prelude::*, }; -#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum ExecutionPayloadHeader< @@ -311,6 +311,20 @@ impl } } } +impl serde::Serialize + for ExecutionPayloadHeader +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Bellatrix(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Capella(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Deneb(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + } + } +} #[derive(Debug, PartialEq, Eq)] pub enum ExecutionPayloadHeaderRef< 'a, diff --git a/ethereum-consensus/src/types/signed_beacon_block.rs b/ethereum-consensus/src/types/signed_beacon_block.rs index ba593d4e8..784d72847 100644 --- a/ethereum-consensus/src/types/signed_beacon_block.rs +++ b/ethereum-consensus/src/types/signed_beacon_block.rs @@ -9,7 +9,7 @@ use crate::{ ssz::prelude::*, types::beacon_block::{BeaconBlockRef, BeaconBlockRefMut}, }; -#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum SignedBeaconBlock< @@ -416,3 +416,49 @@ impl< } } } +impl< + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + > serde::Serialize + for SignedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + > +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Phase0(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Altair(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Bellatrix(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Capella(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Deneb(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + } + } +} diff --git a/ethereum-consensus/src/types/signed_blinded_beacon_block.rs b/ethereum-consensus/src/types/signed_blinded_beacon_block.rs index b8a08fe34..09f0cc0b3 100644 --- a/ethereum-consensus/src/types/signed_blinded_beacon_block.rs +++ b/ethereum-consensus/src/types/signed_blinded_beacon_block.rs @@ -7,7 +7,7 @@ use crate::{ ssz::prelude::*, types::blinded_beacon_block::{BlindedBeaconBlockRef, BlindedBeaconBlockRefMut}, }; -#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum SignedBlindedBeaconBlock< @@ -280,3 +280,41 @@ impl< } } } +impl< + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + > serde::Serialize + for SignedBlindedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + > +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Bellatrix(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Capella(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + Self::Deneb(inner) => <_ as serde::Serialize>::serialize(inner, serializer), + } + } +} diff --git a/spec-gen/src/type_generator.rs b/spec-gen/src/type_generator.rs index c9620caf1..e46fa6235 100644 --- a/spec-gen/src/type_generator.rs +++ b/spec-gen/src/type_generator.rs @@ -356,7 +356,7 @@ fn derive_type_defn(target_type: &Type, merge_type: &MergeType) -> (Item, Generi }) .collect::>(); let enum_defn = parse_quote! { - #[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Serialize, serde::Deserialize)] + #[derive(Debug, Clone, PartialEq, Eq, SimpleSerialize, serde::Deserialize)] #[serde(tag = "version", content = "data")] #[serde(rename_all = "lowercase")] pub enum #type_name #generics { @@ -678,13 +678,9 @@ fn derive_fields_impl( fields } -fn derive_impl_defn( - target_type: &Type, - merge_type: &MergeType, - generics: syn::Generics, -) -> syn::Item { +fn derive_impl_defn(target_type: &Type, merge_type: &MergeType, generics: &Generics) -> syn::Item { let type_name = as_syn_ident(target_type.name()); - let arguments = generics_to_arguments(&generics); + let arguments = generics_to_arguments(generics); let fields_impl = derive_fields_impl(target_type, &type_name, merge_type, None); parse_quote! { impl #generics #type_name #arguments { @@ -814,13 +810,42 @@ fn derive_ref_impl(target_type: &Type, merge_type: &MergeType, is_mut: bool) -> result } +fn derive_serde_ser_impl(target_type: &Type, generics: &Generics, merge_type: &MergeType) -> Item { + let type_name = as_syn_ident(target_type.name()); + let arguments = generics_to_arguments(generics); + let match_arms: Vec = merge_type + .variants + .iter() + .map(|variant| { + let fork_name = as_syn_ident(format!("{:?}", variant.fork)); + parse_quote! { + Self::#fork_name(inner) => <_ as serde::Serialize>::serialize(inner, serializer) + } + }) + .collect(); + parse_quote! { + impl #generics serde::Serialize for #type_name #arguments { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer + { + match self { + #(#match_arms,)* + } + } + } + } +} + fn as_syn(target_type: &Type, merge_type: &MergeType) -> Vec { let (type_defn, generics) = derive_type_defn(target_type, merge_type); - let impl_defn = derive_impl_defn(target_type, merge_type, generics); + let impl_defn = derive_impl_defn(target_type, merge_type, &generics); + + let serde_ser_impl = derive_serde_ser_impl(target_type, &generics, merge_type); let imports = target_type.imports(); - let mut result = vec![imports, type_defn, impl_defn]; + let mut result = vec![imports, type_defn, impl_defn, serde_ser_impl]; if target_type.needs_ref_types() { result.extend(derive_ref_impl(target_type, merge_type, false));