From b92786ab510c101eb6760f91929fe2afdb7cda26 Mon Sep 17 00:00:00 2001 From: Mac L Date: Tue, 14 May 2024 00:34:04 +1000 Subject: [PATCH] Add ExecutionWitness to Payload --- Cargo.lock | 3 +- Cargo.toml | 1 + beacon_node/client/src/notifier.rs | 20 +- beacon_node/execution_layer/src/block_hash.rs | 9 + beacon_node/execution_layer/src/engine_api.rs | 52 +++-- .../src/engine_api/json_structures.rs | 213 +++++++++++++++++- beacon_node/execution_layer/src/lib.rs | 1 + .../test_utils/execution_block_generator.rs | 3 +- .../src/test_utils/handle_rpc.rs | 4 + beacon_node/src/config.rs | 13 +- consensus/types/src/chain_spec.rs | 1 + consensus/types/src/eth_spec.rs | 79 ++++++- consensus/types/src/execution_block_header.rs | 4 + consensus/types/src/execution_payload.rs | 2 + .../types/src/execution_payload_header.rs | 5 + consensus/types/src/lib.rs | 6 +- consensus/types/src/payload.rs | 69 +++++- consensus/types/src/preset.rs | 25 +- consensus/types/src/test_utils/test_random.rs | 19 ++ 19 files changed, 472 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d798e9b8f2a..7f1a8fb02a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7810,8 +7810,7 @@ dependencies = [ [[package]] name = "ssz_types" version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382939886cb24ee8ac885d09116a60f6262d827c7a9e36012b4f6d3d0116d0b3" +source = "git+https://github.com/macladson/ssz_types.git?branch=optional#6a187e66213d42c748e477585ec43e79d057f2cf" dependencies = [ "arbitrary", "derivative", diff --git a/Cargo.toml b/Cargo.toml index 38018c712d5..1869b4ee5ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -234,6 +234,7 @@ validator_dir = { path = "common/validator_dir" } warp_utils = { path = "common/warp_utils" } [patch.crates-io] +ssz_types = { git = "https://github.com/macladson/ssz_types.git", branch = "optional" } yamux = { git = "https://github.com/sigp/rust-yamux.git" } [profile.maxperf] diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index 912babdae31..a2e5023d81a 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -549,17 +549,15 @@ async fn electra_readiness_logging( beacon_chain: &BeaconChain, log: &Logger, ) { - // TODO(electra): Once Electra has features, this code can be swapped back. - let electra_completed = false; - //let electra_completed = beacon_chain - // .canonical_head - // .cached_head() - // .snapshot - // .beacon_block - // .message() - // .body() - // .execution_payload() - // .map_or(false, |payload| payload.electra_placeholder().is_ok()); + let electra_completed = beacon_chain + .canonical_head + .cached_head() + .snapshot + .beacon_block + .message() + .body() + .execution_payload() + .map_or(false, |payload| payload.execution_witness_root().is_ok()); let has_execution_layer = beacon_chain.execution_layer.is_some(); diff --git a/beacon_node/execution_layer/src/block_hash.rs b/beacon_node/execution_layer/src/block_hash.rs index 1f8c29f6b25..33d3dd2fb1a 100644 --- a/beacon_node/execution_layer/src/block_hash.rs +++ b/beacon_node/execution_layer/src/block_hash.rs @@ -36,6 +36,9 @@ pub fn calculate_execution_block_hash( None }; + // TODO(mac): Fix rlp calc + let rlp_execution_witness_root = None; + let rlp_blob_gas_used = payload.blob_gas_used().ok(); let rlp_excess_blob_gas = payload.excess_blob_gas().ok(); @@ -48,6 +51,7 @@ pub fn calculate_execution_block_hash( rlp_blob_gas_used, rlp_excess_blob_gas, parent_beacon_block_root, + rlp_execution_witness_root, ); // Hash the RLP encoding of the block header. @@ -137,6 +141,7 @@ mod test { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, + execution_witness_root: None, }; let expected_rlp = "f90200a0e0a94a7a3c9617401586b1a27025d2d9671332d22d540e0af72b069170380f2aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ba5e000000000000000000000000000000000000a0ec3c94b18b8a1cff7d60f8d258ec723312932928626b4c9355eb4ab3568ec7f7a050f738580ed699f0469702c7ccc63ed2e51bc034be9479b7bff4e68dee84accfa029b0562f7140574dd0d50dee8a271b22e1a0a7b78fca58f7c60370d8317ba2a9b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000188016345785d8a00008301553482079e42a0000000000000000000000000000000000000000000000000000000000000000088000000000000000082036b"; let expected_hash = @@ -168,6 +173,7 @@ mod test { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, + execution_witness_root: None, }; let expected_rlp = "f901fda0927ca537f06c783a3a2635b8805eef1c8c2124f7444ad4a3389898dd832f2dbea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ba5e000000000000000000000000000000000000a0e97859b065bd8dbbb4519c7cb935024de2484c2b7f881181b4360492f0b06b82a050f738580ed699f0469702c7ccc63ed2e51bc034be9479b7bff4e68dee84accfa029b0562f7140574dd0d50dee8a271b22e1a0a7b78fca58f7c60370d8317ba2a9b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a00008301553482079e42a0000000000000000000000000000000000000000000000000000000000002000088000000000000000082036b"; let expected_hash = @@ -200,6 +206,7 @@ mod test { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, + execution_witness_root: None, }; let expected_hash = Hash256::from_str("6da69709cd5a34079b6604d29cd78fc01dacd7c6268980057ad92a2bede87351") @@ -230,6 +237,7 @@ mod test { blob_gas_used: Some(0x0u64), excess_blob_gas: Some(0x0u64), parent_beacon_block_root: Some(Hash256::from_str("f7d327d2c04e4f12e9cdd492e53d39a1d390f8b1571e3b2a22ac6e1e170e5b1a").unwrap()), + execution_witness_root: None, }; let expected_hash = Hash256::from_str("a7448e600ead0a23d16f96aa46e8dea9eef8a7c5669a5f0a5ff32709afe9c408") @@ -260,6 +268,7 @@ mod test { blob_gas_used: Some(0x0u64), excess_blob_gas: Some(0x0u64), parent_beacon_block_root: Some(Hash256::from_str("f7d327d2c04e4f12e9cdd492e53d39a1d390f8b1571e3b2a22ac6e1e170e5b1a").unwrap()), + execution_witness_root: None, }; let expected_hash = Hash256::from_str("a7448e600ead0a23d16f96aa46e8dea9eef8a7c5669a5f0a5ff32709afe9c408") diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index a91f5d6a442..bb00d5be1d8 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -21,8 +21,8 @@ use strum::IntoStaticStr; use superstruct::superstruct; pub use types::{ Address, BeaconBlockRef, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadHeader, - ExecutionPayloadRef, FixedVector, ForkName, Hash256, Transactions, Uint256, VariableList, - Withdrawal, Withdrawals, + ExecutionPayloadRef, ExecutionWitness, FixedVector, ForkName, Hash256, Transactions, Uint256, + VariableList, Withdrawal, Withdrawals, }; use types::{ @@ -197,6 +197,8 @@ pub struct ExecutionBlockWithTransactions { #[superstruct(only(Deneb, Electra))] #[serde(with = "serde_utils::u64_hex_be")] pub excess_blob_gas: u64, + #[superstruct(only(Electra))] + pub execution_witness: ExecutionWitness, } impl TryFrom> for ExecutionBlockWithTransactions { @@ -302,6 +304,7 @@ impl TryFrom> for ExecutionBlockWithTransactions .collect(), blob_gas_used: block.blob_gas_used, excess_blob_gas: block.excess_blob_gas, + execution_witness: block.execution_witness, }) } }; @@ -521,6 +524,7 @@ impl GetPayloadResponse { pub struct ExecutionPayloadBodyV1 { pub transactions: Transactions, pub withdrawals: Option>, + pub execution_witness: Option>, } impl ExecutionPayloadBodyV1 { @@ -609,25 +613,31 @@ impl ExecutionPayloadBodyV1 { } ExecutionPayloadHeader::Electra(header) => { if let Some(withdrawals) = self.withdrawals { - Ok(ExecutionPayload::Electra(ExecutionPayloadElectra { - parent_hash: header.parent_hash, - fee_recipient: header.fee_recipient, - state_root: header.state_root, - receipts_root: header.receipts_root, - logs_bloom: header.logs_bloom, - prev_randao: header.prev_randao, - block_number: header.block_number, - gas_limit: header.gas_limit, - gas_used: header.gas_used, - timestamp: header.timestamp, - extra_data: header.extra_data, - base_fee_per_gas: header.base_fee_per_gas, - block_hash: header.block_hash, - transactions: self.transactions, - withdrawals, - blob_gas_used: header.blob_gas_used, - excess_blob_gas: header.excess_blob_gas, - })) + if let Some(execution_witness) = self.execution_witness { + Ok(ExecutionPayload::Electra(ExecutionPayloadElectra { + parent_hash: header.parent_hash, + fee_recipient: header.fee_recipient, + state_root: header.state_root, + receipts_root: header.receipts_root, + logs_bloom: header.logs_bloom, + prev_randao: header.prev_randao, + block_number: header.block_number, + gas_limit: header.gas_limit, + gas_used: header.gas_used, + timestamp: header.timestamp, + extra_data: header.extra_data, + base_fee_per_gas: header.base_fee_per_gas, + block_hash: header.block_hash, + transactions: self.transactions, + withdrawals, + blob_gas_used: header.blob_gas_used, + excess_blob_gas: header.excess_blob_gas, + execution_witness, + })) + } else { + Err(format!( + "block {} is post-electra but payload body doesn't have an execution witness", header.block_hash)) + } } else { Err(format!( "block {} is post-capella but payload body doesn't have withdrawals", diff --git a/beacon_node/execution_layer/src/engine_api/json_structures.rs b/beacon_node/execution_layer/src/engine_api/json_structures.rs index 9f2387ae314..896d6158d54 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -4,7 +4,15 @@ use strum::EnumString; use superstruct::superstruct; use types::beacon_block_body::KzgCommitments; use types::blob_sidecar::BlobsList; -use types::{FixedVector, Unsigned}; +use types::{ + execution_witness::{ + BanderwagonFieldElement, BanderwagonGroupElement, IpaProof, StateDiff, StateDiffValue, + Stem, StemStateDiff, StemValue, SuffixStateDiff, VerkleProof, + }, + ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadElectra, ExecutionPayloadMerge, + ExecutionWitness, +}; +use types::{FixedVector, Optional, Unsigned, VariableList}; #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -101,6 +109,9 @@ pub struct JsonExecutionPayload { #[superstruct(only(V3, V4))] #[serde(with = "serde_utils::u64_hex_be")] pub excess_blob_gas: u64, + #[superstruct(only(V4))] + #[serde(deserialize_with = "serde_execution_witness")] + pub execution_witness: JsonExecutionWitness, } impl From> for JsonExecutionPayloadV1 { @@ -203,6 +214,7 @@ impl From> for JsonExecutionPayloadV4 .into(), blob_gas_used: payload.blob_gas_used, excess_blob_gas: payload.excess_blob_gas, + execution_witness: payload.execution_witness.into(), } } } @@ -319,6 +331,7 @@ impl From> for ExecutionPayloadElectra .into(), blob_gas_used: payload.blob_gas_used, excess_blob_gas: payload.excess_blob_gas, + execution_witness: payload.execution_witness.into(), } } } @@ -691,6 +704,7 @@ pub struct JsonExecutionPayloadBodyV1 { #[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")] pub transactions: Transactions, pub withdrawals: Option>, + pub execution_witness: Option>, } impl From> for ExecutionPayloadBodyV1 { @@ -705,6 +719,7 @@ impl From> for ExecutionPayloadBodyV1< .collect::>(), ) }), + execution_witness: value.execution_witness.map(Into::into), } } } @@ -747,3 +762,199 @@ pub mod serde_logs_bloom { .map_err(|e| serde::de::Error::custom(format!("invalid logs bloom: {:?}", e))) } } + +pub fn serde_execution_witness<'de, D, T>(deserializer: D) -> Result +where + T: Default + Deserialize<'de>, + D: serde::Deserializer<'de>, +{ + let opt = Option::deserialize(deserializer)?; + Ok(opt.unwrap_or_default()) +} + +/// Execution Witness JSON types. +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonSuffixStateDiff { + //#[serde(with = "eth2_serde_utils::quoted_u8")] + suffix: u8, + // `None` means not currently present. + current_value: Optional>, + // `None` means value is not updated. + new_value: Optional>, +} + +impl From> for SuffixStateDiff { + fn from(value: JsonSuffixStateDiff) -> Self { + Self { + suffix: value.suffix, + current_value: value.current_value, + new_value: value.new_value, + } + } +} + +impl From> for JsonSuffixStateDiff { + fn from(value: SuffixStateDiff) -> Self { + Self { + suffix: value.suffix, + current_value: value.current_value, + new_value: value.new_value, + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonStemStateDiff { + stem: Stem, + suffix_diffs: VariableList, E::MaxVerkleWidth>, +} + +impl From> for StemStateDiff { + fn from(value: JsonStemStateDiff) -> Self { + Self { + stem: value.stem, + suffix_diffs: value + .suffix_diffs + .into_iter() + .map(Into::into) + .collect::>() + .into(), + } + } +} + +impl From> for JsonStemStateDiff { + fn from(value: StemStateDiff) -> Self { + Self { + stem: value.stem, + suffix_diffs: value + .suffix_diffs + .into_iter() + .map(Into::into) + .collect::>() + .into(), + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonIpaProof { + cl: FixedVector, E::IpaProofDepth>, + cr: FixedVector, E::IpaProofDepth>, + final_evaluation: BanderwagonFieldElement, +} + +impl From> for IpaProof { + fn from(value: JsonIpaProof) -> Self { + Self { + cl: value.cl, + cr: value.cr, + final_evaluation: value.final_evaluation, + } + } +} + +impl From> for JsonIpaProof { + fn from(value: IpaProof) -> Self { + Self { + cl: value.cl, + cr: value.cr, + final_evaluation: value.final_evaluation, + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonVerkleProof { + other_stems: VariableList, E::MaxStems>, + #[serde(with = "ssz_types::serde_utils::hex_var_list")] + depth_extension_present: VariableList, + commitments_by_path: VariableList, E::MaxCommittments>, + d: BanderwagonGroupElement, + ipa_proof: JsonIpaProof, +} + +impl From> for VerkleProof { + fn from(value: JsonVerkleProof) -> Self { + Self { + other_stems: value.other_stems, + depth_extension_present: value.depth_extension_present, + commitments_by_path: value.commitments_by_path, + d: value.d, + ipa_proof: IpaProof::::from(value.ipa_proof), + } + } +} + +impl From> for JsonVerkleProof { + fn from(value: VerkleProof) -> Self { + Self { + other_stems: value.other_stems, + depth_extension_present: value.depth_extension_present, + commitments_by_path: value.commitments_by_path, + d: value.d, + ipa_proof: JsonIpaProof::::from(value.ipa_proof), + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", transparent)] +pub struct JsonStateDiff { + inner: VariableList, E::MaxStems>, +} + +impl From> for StateDiff { + fn from(value: JsonStateDiff) -> Self { + Self { + inner: value + .inner + .into_iter() + .map(Into::into) + .collect::>() + .into(), + } + } +} + +impl From> for JsonStateDiff { + fn from(value: StateDiff) -> Self { + Self { + inner: value + .inner + .into_iter() + .map(Into::into) + .collect::>() + .into(), + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonExecutionWitness { + state_diff: JsonStateDiff, + verkle_proof: JsonVerkleProof, +} + +impl From> for ExecutionWitness { + fn from(value: JsonExecutionWitness) -> Self { + Self { + state_diff: StateDiff::::from(value.state_diff), + verkle_proof: VerkleProof::::from(value.verkle_proof), + } + } +} + +impl From> for JsonExecutionWitness { + fn from(value: ExecutionWitness) -> Self { + Self { + state_diff: JsonStateDiff::::from(value.state_diff), + verkle_proof: JsonVerkleProof::::from(value.verkle_proof), + } + } +} diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 30930318eff..4e42b37575e 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -1974,6 +1974,7 @@ impl ExecutionLayer { withdrawals, blob_gas_used: electra_block.blob_gas_used, excess_blob_gas: electra_block.excess_blob_gas, + execution_witness: electra_block.execution_witness, }) } }; diff --git a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs index 87484ced67c..73926982d3b 100644 --- a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs +++ b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs @@ -23,7 +23,7 @@ use tree_hash_derive::TreeHash; use types::{ Blob, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadHeader, ExecutionPayloadMerge, - ForkName, Hash256, Transaction, Transactions, Uint256, + ExecutionWitness, ForkName, Hash256, Transaction, Transactions, Uint256, }; use super::DEFAULT_TERMINAL_BLOCK; @@ -646,6 +646,7 @@ impl ExecutionBlockGenerator { withdrawals: pa.withdrawals.clone().into(), blob_gas_used: 0, excess_blob_gas: 0, + execution_witness: ExecutionWitness::default(), }), _ => unreachable!(), }, diff --git a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs index 77d972ab88e..73cde54a0ae 100644 --- a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs +++ b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs @@ -569,6 +569,10 @@ pub async fn handle_rpc( .withdrawals() .ok() .map(|withdrawals| VariableList::from(withdrawals.clone())), + execution_witness: block + .execution_witness() + .ok() + .map(|witness| witness.clone().into()), })); } None => response.push(None), diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 3ba89595ac4..bd4a8d24cbd 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -412,9 +412,11 @@ pub fn get_config( .map_err(|_| "auto-compact-db takes a boolean".to_string())?; } - if let Some(prune_payloads) = clap_utils::parse_optional(cli_args, "prune-payloads")? { - client_config.store.prune_payloads = prune_payloads; - } + //TODO(mac): Re-enable prune payloads once Geth supports it. + client_config.store.prune_payloads = false; + //if let Some(prune_payloads) = clap_utils::parse_optional(cli_args, "prune-payloads")? { + // client_config.store.prune_payloads = prune_payloads; + //} if let Some(epochs_per_migration) = clap_utils::parse_optional(cli_args, "epochs-per-migration")? @@ -825,8 +827,9 @@ pub fn get_config( } // Optimistic finalized sync. - client_config.chain.optimistic_finalized_sync = - !cli_args.is_present("disable-optimistic-finalized-sync"); + client_config.chain.optimistic_finalized_sync = false; + // TODO(mac) remove this once optimistic finalized sync is working. + // !cli_args.is_present("disable-optimistic-finalized-sync"); if cli_args.is_present("genesis-backfill") { client_config.chain.genesis_backfill = true; diff --git a/consensus/types/src/chain_spec.rs b/consensus/types/src/chain_spec.rs index 56329e6ba4c..3893610454d 100644 --- a/consensus/types/src/chain_spec.rs +++ b/consensus/types/src/chain_spec.rs @@ -1640,6 +1640,7 @@ where mod tests { use super::*; use itertools::Itertools; + use safe_arith::SafeArith; #[test] fn test_mainnet_spec_can_be_constructed() { diff --git a/consensus/types/src/eth_spec.rs b/consensus/types/src/eth_spec.rs index a2972b722a2..5938979d842 100644 --- a/consensus/types/src/eth_spec.rs +++ b/consensus/types/src/eth_spec.rs @@ -3,8 +3,8 @@ use crate::*; use safe_arith::SafeArith; use serde::{Deserialize, Serialize}; use ssz_types::typenum::{ - bit::B0, UInt, U0, U1024, U1048576, U1073741824, U1099511627776, U128, U131072, U16, U16777216, - U2, U2048, U256, U32, U4, U4096, U512, U6, U625, U64, U65536, U8, U8192, + bit::B0, Prod, UInt, U0, U1024, U1048576, U1073741824, U1099511627776, U128, U131072, U16, + U16777216, U2, U2048, U256, U31, U32, U33, U4, U4096, U512, U6, U625, U64, U65536, U8, U8192, }; use ssz_types::typenum::{U17, U9}; use std::fmt::{self, Debug}; @@ -111,6 +111,17 @@ pub trait EthSpec: type FieldElementsPerBlob: Unsigned + Clone + Sync + Send + Debug + PartialEq; type BytesPerFieldElement: Unsigned + Clone + Sync + Send + Debug + PartialEq; type KzgCommitmentInclusionProofDepth: Unsigned + Clone + Sync + Send + Debug + PartialEq; + /* + * New in Electra + */ + type BytesPerBanderwagonElement: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxStems: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxStemLength: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxCommittmentsPerStem: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxCommittments: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type BytesPerSuffixStateDiffValue: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxVerkleWidth: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type IpaProofDepth: Unsigned + Clone + Sync + Send + Debug + PartialEq; /* * Derived values (set these CAREFULLY) */ @@ -134,11 +145,6 @@ pub trait EthSpec: /// Must be set to `BytesPerFieldElement * FieldElementsPerBlob`. type BytesPerBlob: Unsigned + Clone + Sync + Send + Debug + PartialEq; - /* - * New in Electra - */ - type ElectraPlaceholder: Unsigned + Clone + Sync + Send + Debug + PartialEq; - fn default_spec() -> ChainSpec; fn spec_name() -> EthSpecId; @@ -284,8 +290,36 @@ pub trait EthSpec: Self::KzgCommitmentInclusionProofDepth::to_usize() } - fn electra_placeholder() -> usize { - Self::ElectraPlaceholder::to_usize() + fn bytes_per_banderwagon_element() -> usize { + Self::BytesPerBanderwagonElement::to_usize() + } + + fn max_stems() -> usize { + Self::MaxStems::to_usize() + } + + fn max_stem_length() -> usize { + Self::MaxStemLength::to_usize() + } + + fn max_committments_per_stem() -> usize { + Self::MaxCommittmentsPerStem::to_usize() + } + + fn max_committments() -> usize { + Self::MaxCommittments::to_usize() + } + + fn bytes_per_suffix_state_diff_value() -> usize { + Self::BytesPerSuffixStateDiffValue::to_usize() + } + + fn max_verkle_width() -> usize { + Self::MaxVerkleWidth::to_usize() + } + + fn ipa_proof_depth() -> usize { + Self::IpaProofDepth::to_usize() } } @@ -337,7 +371,14 @@ impl EthSpec for MainnetEthSpec { type SlotsPerEth1VotingPeriod = U2048; // 64 epochs * 32 slots per epoch type MaxBlsToExecutionChanges = U16; type MaxWithdrawalsPerPayload = U16; - type ElectraPlaceholder = U16; + type BytesPerBanderwagonElement = U32; + type MaxStems = U65536; + type MaxStemLength = U31; + type MaxCommittmentsPerStem = U33; + type MaxCommittments = Prod; + type BytesPerSuffixStateDiffValue = U32; + type MaxVerkleWidth = U256; + type IpaProofDepth = U8; fn default_spec() -> ChainSpec { ChainSpec::mainnet() @@ -390,7 +431,14 @@ impl EthSpec for MinimalEthSpec { MaxBlsToExecutionChanges, MaxBlobsPerBlock, BytesPerFieldElement, - ElectraPlaceholder + BytesPerBanderwagonElement, + MaxStems, + MaxStemLength, + MaxCommittmentsPerStem, + MaxCommittments, + BytesPerSuffixStateDiffValue, + MaxVerkleWidth, + IpaProofDepth }); fn default_spec() -> ChainSpec { @@ -442,7 +490,14 @@ impl EthSpec for GnosisEthSpec { type BytesPerFieldElement = U32; type BytesPerBlob = U131072; type KzgCommitmentInclusionProofDepth = U17; - type ElectraPlaceholder = U16; + type BytesPerBanderwagonElement = U32; + type MaxStems = U65536; + type MaxStemLength = U31; + type MaxCommittmentsPerStem = U33; + type MaxCommittments = Prod; + type BytesPerSuffixStateDiffValue = U32; + type MaxVerkleWidth = U256; + type IpaProofDepth = U8; fn default_spec() -> ChainSpec { ChainSpec::gnosis() diff --git a/consensus/types/src/execution_block_header.rs b/consensus/types/src/execution_block_header.rs index 945222a9258..2560e47ec19 100644 --- a/consensus/types/src/execution_block_header.rs +++ b/consensus/types/src/execution_block_header.rs @@ -51,9 +51,11 @@ pub struct ExecutionBlockHeader { pub blob_gas_used: Option, pub excess_blob_gas: Option, pub parent_beacon_block_root: Option, + pub execution_witness_root: Option, } impl ExecutionBlockHeader { + #[allow(clippy::too_many_arguments)] pub fn from_payload( payload: ExecutionPayloadRef, rlp_empty_list_root: Hash256, @@ -62,6 +64,7 @@ impl ExecutionBlockHeader { rlp_blob_gas_used: Option, rlp_excess_blob_gas: Option, rlp_parent_beacon_block_root: Option, + rlp_execution_witness_root: Option, ) -> Self { // Most of these field mappings are defined in EIP-3675 except for `mixHash`, which is // defined in EIP-4399. @@ -86,6 +89,7 @@ impl ExecutionBlockHeader { blob_gas_used: rlp_blob_gas_used, excess_blob_gas: rlp_excess_blob_gas, parent_beacon_block_root: rlp_parent_beacon_block_root, + execution_witness_root: rlp_execution_witness_root, } } } diff --git a/consensus/types/src/execution_payload.rs b/consensus/types/src/execution_payload.rs index 27dc8cab0a4..03ee0918fa8 100644 --- a/consensus/types/src/execution_payload.rs +++ b/consensus/types/src/execution_payload.rs @@ -89,6 +89,8 @@ pub struct ExecutionPayload { #[superstruct(only(Deneb, Electra), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub excess_blob_gas: u64, + #[superstruct(only(Electra))] + pub execution_witness: ExecutionWitness, } impl<'a, E: EthSpec> ExecutionPayloadRef<'a, E> { diff --git a/consensus/types/src/execution_payload_header.rs b/consensus/types/src/execution_payload_header.rs index f10f449d6de..5caaf9800d0 100644 --- a/consensus/types/src/execution_payload_header.rs +++ b/consensus/types/src/execution_payload_header.rs @@ -87,6 +87,9 @@ pub struct ExecutionPayloadHeader { #[serde(with = "serde_utils::quoted_u64")] #[superstruct(getter(copy))] pub excess_blob_gas: u64, + #[superstruct(only(Electra))] + #[superstruct(getter(copy))] + pub execution_witness_root: Hash256, } impl ExecutionPayloadHeader { @@ -186,6 +189,7 @@ impl ExecutionPayloadHeaderDeneb { withdrawals_root: self.withdrawals_root, blob_gas_used: self.blob_gas_used, excess_blob_gas: self.excess_blob_gas, + execution_witness_root: Hash256::zero(), } } } @@ -277,6 +281,7 @@ impl<'a, E: EthSpec> From<&'a ExecutionPayloadElectra> for ExecutionPayloadHe withdrawals_root: payload.withdrawals.tree_hash_root(), blob_gas_used: payload.blob_gas_used, excess_blob_gas: payload.excess_blob_gas, + execution_witness_root: payload.execution_witness.tree_hash_root(), } } } diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index 95b32796fd5..23fb1e864a9 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -41,6 +41,7 @@ pub mod eth_spec; pub mod execution_block_hash; pub mod execution_payload; pub mod execution_payload_header; +pub mod execution_witness; pub mod fork; pub mod fork_data; pub mod fork_name; @@ -149,6 +150,7 @@ pub use crate::execution_payload_header::{ ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, }; +pub use crate::execution_witness::ExecutionWitness; pub use crate::fork::Fork; pub use crate::fork_context::ForkContext; pub use crate::fork_data::ForkData; @@ -242,5 +244,7 @@ pub use bls::{ pub use kzg::{KzgCommitment, KzgProof, VERSIONED_HASH_VERSION_KZG}; -pub use ssz_types::{typenum, typenum::Unsigned, BitList, BitVector, FixedVector, VariableList}; +pub use ssz_types::{ + typenum, typenum::Unsigned, BitList, BitVector, FixedVector, Optional, VariableList, +}; pub use superstruct::superstruct; diff --git a/consensus/types/src/payload.rs b/consensus/types/src/payload.rs index 18b3199bd35..72ca3125b06 100644 --- a/consensus/types/src/payload.rs +++ b/consensus/types/src/payload.rs @@ -39,6 +39,7 @@ pub trait ExecPayload: Debug + Clone + PartialEq + Hash + TreeHash + /// fork-specific fields fn withdrawals_root(&self) -> Result; fn blob_gas_used(&self) -> Result; + fn execution_witness_root(&self) -> Result; /// Is this a default payload with 0x0 roots for transactions and withdrawals? fn is_default_with_zero_roots(&self) -> bool; @@ -273,6 +274,17 @@ impl ExecPayload for FullPayload { } } + fn execution_witness_root(&self) -> Result { + match self { + FullPayload::Merge(_) => Err(Error::IncorrectStateVariant), + FullPayload::Capella(_) => Err(Error::IncorrectStateVariant), + FullPayload::Deneb(_) => Err(Error::IncorrectStateVariant), + FullPayload::Electra(ref inner) => { + Ok(inner.execution_payload.execution_witness.tree_hash_root()) + } + } + } + fn is_default_with_zero_roots<'a>(&'a self) -> bool { map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| { cons(payload); @@ -405,6 +417,17 @@ impl<'b, E: EthSpec> ExecPayload for FullPayloadRef<'b, E> { } } + fn execution_witness_root(&self) -> Result { + match self { + FullPayloadRef::Merge(_) => Err(Error::IncorrectStateVariant), + FullPayloadRef::Capella(_) => Err(Error::IncorrectStateVariant), + FullPayloadRef::Deneb(_) => Err(Error::IncorrectStateVariant), + FullPayloadRef::Electra(inner) => { + Ok(inner.execution_payload.execution_witness.tree_hash_root()) + } + } + } + fn is_default_with_zero_roots<'a>(&'a self) -> bool { map_full_payload_ref!(&'a _, self, move |payload, cons| { cons(payload); @@ -582,6 +605,17 @@ impl ExecPayload for BlindedPayload { } } + fn execution_witness_root(&self) -> Result { + match self { + BlindedPayload::Merge(_) => Err(Error::IncorrectStateVariant), + BlindedPayload::Capella(_) => Err(Error::IncorrectStateVariant), + BlindedPayload::Deneb(_) => Err(Error::IncorrectStateVariant), + BlindedPayload::Electra(ref inner) => { + Ok(inner.execution_payload_header.execution_witness_root) + } + } + } + fn is_default_with_zero_roots(&self) -> bool { self.to_ref().is_default_with_zero_roots() } @@ -683,6 +717,17 @@ impl<'b, E: EthSpec> ExecPayload for BlindedPayloadRef<'b, E> { } } + fn execution_witness_root(&self) -> Result { + match self { + BlindedPayloadRef::Merge(_) => Err(Error::IncorrectStateVariant), + BlindedPayloadRef::Capella(_) => Err(Error::IncorrectStateVariant), + BlindedPayloadRef::Deneb(_) => Err(Error::IncorrectStateVariant), + BlindedPayloadRef::Electra(inner) => { + Ok(inner.execution_payload_header.execution_witness_root) + } + } + } + fn is_default_with_zero_roots<'a>(&'a self) -> bool { map_blinded_payload_ref!(&'b _, self, move |payload, cons| { cons(payload); @@ -709,7 +754,8 @@ macro_rules! impl_exec_payload_common { $is_default_with_empty_roots:block, $f:block, $g:block, - $h:block) => { + $h:block, + $i:block) => { impl ExecPayload for $wrapper_type { fn block_type() -> BlockType { BlockType::$block_type_variant @@ -772,6 +818,11 @@ macro_rules! impl_exec_payload_common { let h = $h; h(self) } + + fn execution_witness_root(&self) -> Result { + let i = $i; + i(self) + } } impl From<$wrapped_type> for $wrapper_type { @@ -817,6 +868,14 @@ macro_rules! impl_exec_payload_for_fork { wrapper_ref_type.blob_gas_used() }; c + }, + { + let c: for<'a> fn(&'a $wrapper_type_header) -> Result = + |payload: &$wrapper_type_header| { + let wrapper_ref_type = BlindedPayloadRef::$fork_variant(&payload); + wrapper_ref_type.execution_witness_root() + }; + c } ); @@ -904,6 +963,14 @@ macro_rules! impl_exec_payload_for_fork { wrapper_ref_type.blob_gas_used() }; c + }, + { + let c: for<'a> fn(&'a $wrapper_type_full) -> Result = + |payload: &$wrapper_type_full| { + let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload); + wrapper_ref_type.execution_witness_root() + }; + c } ); diff --git a/consensus/types/src/preset.rs b/consensus/types/src/preset.rs index 626a45d971d..33d98ffd69a 100644 --- a/consensus/types/src/preset.rs +++ b/consensus/types/src/preset.rs @@ -230,13 +230,34 @@ impl DenebPreset { #[serde(rename_all = "UPPERCASE")] pub struct ElectraPreset { #[serde(with = "serde_utils::quoted_u64")] - pub electra_placeholder: u64, + pub bytes_per_banderwagon_element: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_stems: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_stem_length: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_committments_per_stem: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_committments: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub bytes_per_suffix_state_diff_value: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_verkle_width: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub ipa_proof_depth: u64, } impl ElectraPreset { pub fn from_chain_spec(_spec: &ChainSpec) -> Self { Self { - electra_placeholder: 0, + bytes_per_banderwagon_element: E::bytes_per_banderwagon_element() as u64, + max_stems: E::max_stems() as u64, + max_stem_length: E::max_stem_length() as u64, + max_committments_per_stem: E::max_committments_per_stem() as u64, + max_committments: E::max_committments() as u64, + bytes_per_suffix_state_diff_value: E::bytes_per_suffix_state_diff_value() as u64, + max_verkle_width: E::max_verkle_width() as u64, + ipa_proof_depth: E::ipa_proof_depth() as u64, } } } diff --git a/consensus/types/src/test_utils/test_random.rs b/consensus/types/src/test_utils/test_random.rs index 0adaf81bd7d..45674cc4135 100644 --- a/consensus/types/src/test_utils/test_random.rs +++ b/consensus/types/src/test_utils/test_random.rs @@ -87,6 +87,18 @@ where } } +impl TestRandom for Option +where + U: TestRandom, +{ + fn random_for_test(rng: &mut impl RngCore) -> Self { + match bool::random_for_test(rng) { + false => None, + true => Some(U::random_for_test(rng)), + } + } +} + impl TestRandom for FixedVector where T: TestRandom, @@ -118,6 +130,13 @@ where } } +// TODO(mac) Dummy impl +impl TestRandom for Optional { + fn random_for_test(_rng: &mut impl RngCore) -> Self { + Self::from(None) + } +} + macro_rules! impl_test_random_for_u8_array { ($len: expr) => { impl TestRandom for [u8; $len] {