From c1d47da02de79157156677a49511a503ff0e333f Mon Sep 17 00:00:00 2001 From: ethDreamer <37123614+ethDreamer@users.noreply.github.com> Date: Thu, 27 Apr 2023 13:18:21 -0500 Subject: [PATCH] Update `engine_api` to latest version (#4223) * Update Engine API to Latest * Get Mock EE Working * Fix Mock EE * Update Engine API Again * Rip out get_blobs_bundle Stuff * Fix Test Harness * Fix Clippy Complaints * Fix Beacon Chain Tests --- Cargo.lock | 1 + beacon_node/beacon_chain/src/beacon_chain.rs | 20 ++- .../beacon_chain/src/blob_verification.rs | 20 ++- beacon_node/beacon_chain/src/test_utils.rs | 82 ++++++++++-- .../beacon_chain/tests/block_verification.rs | 10 +- .../tests/payload_invalidation.rs | 16 ++- beacon_node/beacon_chain/tests/store_tests.rs | 8 +- beacon_node/execution_layer/Cargo.toml | 1 + beacon_node/execution_layer/src/engine_api.rs | 20 ++- .../execution_layer/src/engine_api/http.rs | 20 --- .../src/engine_api/json_structures.rs | 32 ++++- beacon_node/execution_layer/src/lib.rs | 124 +++++++++--------- .../test_utils/execution_block_generator.rs | 124 +++++++++++++++++- .../src/test_utils/handle_rpc.rs | 10 +- .../src/test_utils/mock_execution_layer.rs | 4 + .../execution_layer/src/test_utils/mod.rs | 12 +- .../http_api/tests/interactive_tests.rs | 20 ++- .../network/src/beacon_processor/tests.rs | 16 +-- consensus/fork_choice/tests/tests.rs | 22 ++-- consensus/types/src/blob_sidecar.rs | 29 +++- consensus/types/src/lib.rs | 1 + crypto/kzg/src/kzg_commitment.rs | 13 +- crypto/kzg/src/lib.rs | 1 + testing/node_test_rig/src/lib.rs | 2 +- 24 files changed, 449 insertions(+), 159 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fad095449..89780448d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2647,6 +2647,7 @@ dependencies = [ "hex", "jsonwebtoken", "keccak-hash", + "kzg", "lazy_static", "lighthouse_metrics", "lru 0.7.8", diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 1ea007620..e7180cae1 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -4711,7 +4711,7 @@ impl BeaconChain { bls_to_execution_changes, } = partial_beacon_block; - let (inner_block, blobs_opt) = match &state { + let (inner_block, blobs_opt, proofs_opt) = match &state { BeaconState::Base(_) => ( BeaconBlock::Base(BeaconBlockBase { slot, @@ -4731,6 +4731,7 @@ impl BeaconChain { }, }), None, + None, ), BeaconState::Altair(_) => ( BeaconBlock::Altair(BeaconBlockAltair { @@ -4753,9 +4754,10 @@ impl BeaconChain { }, }), None, + None, ), BeaconState::Merge(_) => { - let (payload, _, _) = block_contents + let (payload, _, _, _) = block_contents .ok_or(BlockProductionError::MissingExecutionPayload)? .deconstruct(); ( @@ -4781,10 +4783,11 @@ impl BeaconChain { }, }), None, + None, ) } BeaconState::Capella(_) => { - let (payload, _, _) = block_contents + let (payload, _, _, _) = block_contents .ok_or(BlockProductionError::MissingExecutionPayload)? .deconstruct(); ( @@ -4811,10 +4814,11 @@ impl BeaconChain { }, }), None, + None, ) } BeaconState::Deneb(_) => { - let (payload, kzg_commitments, blobs) = block_contents + let (payload, kzg_commitments, blobs, proofs) = block_contents .ok_or(BlockProductionError::MissingExecutionPayload)? .deconstruct(); ( @@ -4843,6 +4847,7 @@ impl BeaconChain { }, }), blobs, + proofs, ) } }; @@ -4915,8 +4920,11 @@ impl BeaconChain { ))); } - let kzg_proofs = - Self::compute_blob_kzg_proofs(kzg, &blobs, expected_kzg_commitments, slot)?; + let kzg_proofs = if let Some(proofs) = proofs_opt { + Vec::from(proofs) + } else { + Self::compute_blob_kzg_proofs(kzg, &blobs, expected_kzg_commitments, slot)? + }; kzg_utils::validate_blobs::( kzg, diff --git a/beacon_node/beacon_chain/src/blob_verification.rs b/beacon_node/beacon_chain/src/blob_verification.rs index 1e561cf34..d5e5e9665 100644 --- a/beacon_node/beacon_chain/src/blob_verification.rs +++ b/beacon_node/beacon_chain/src/blob_verification.rs @@ -12,13 +12,14 @@ use crate::data_availability_checker::{ }; use crate::kzg_utils::{validate_blob, validate_blobs}; use crate::BeaconChainError; +use eth2::types::BlockContentsTuple; use kzg::Kzg; use slog::{debug, warn}; use std::borrow::Cow; use types::{ BeaconBlockRef, BeaconState, BeaconStateError, BlobSidecar, BlobSidecarList, ChainSpec, - CloneConfig, Epoch, EthSpec, Hash256, KzgCommitment, RelativeEpoch, SignedBeaconBlock, - SignedBeaconBlockHeader, SignedBlobSidecar, Slot, + CloneConfig, Epoch, EthSpec, FullPayload, Hash256, KzgCommitment, RelativeEpoch, + SignedBeaconBlock, SignedBeaconBlockHeader, SignedBlobSidecar, Slot, }; #[derive(Debug)] @@ -659,3 +660,18 @@ impl From> for BlockWrapper { Self::Block(Arc::new(value)) } } + +impl From>> for BlockWrapper { + fn from(value: BlockContentsTuple>) -> Self { + match value.1 { + Some(variable_list) => Self::BlockAndBlobs( + Arc::new(value.0), + Vec::from(variable_list) + .into_iter() + .map(|signed_blob| signed_blob.message) + .collect::>(), + ), + None => Self::Block(Arc::new(value.0)), + } + } +} diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index c54c3df65..db502fcda 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -1,3 +1,4 @@ +use crate::blob_verification::{AsBlock, BlockWrapper}; pub use crate::persisted_beacon_chain::PersistedBeaconChain; pub use crate::{ beacon_chain::{BEACON_CHAIN_DB_KEY, ETH1_CACHE_DB_KEY, FORK_CHOICE_DB_KEY, OP_POOL_DB_KEY}, @@ -13,6 +14,7 @@ use crate::{ StateSkipConfig, }; use bls::get_withdrawal_credentials; +use eth2::types::BlockContentsTuple; use execution_layer::{ auth::JwtKey, test_utils::{ @@ -25,7 +27,7 @@ use fork_choice::CountUnrealized; use futures::channel::mpsc::Receiver; pub use genesis::{interop_genesis_state_with_eth1, DEFAULT_ETH1_BLOCK_HASH}; use int_to_bytes::int_to_bytes32; -use kzg::TrustedSetup; +use kzg::{Kzg, TrustedSetup}; use merkle_proof::MerkleTree; use parking_lot::Mutex; use parking_lot::RwLockWriteGuard; @@ -446,6 +448,13 @@ where let deneb_time = spec.deneb_fork_epoch.map(|epoch| { HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() }); + + let trusted_setup: TrustedSetup = + serde_json::from_reader(eth2_network_config::TRUSTED_SETUP) + .map_err(|e| format!("Unable to read trusted setup file: {}", e)) + .expect("should have trusted setup"); + let kzg = Kzg::new_from_trusted_setup(trusted_setup).expect("should create kzg"); + let mock = MockExecutionLayer::new( self.runtime.task_executor.clone(), DEFAULT_TERMINAL_BLOCK, @@ -455,6 +464,7 @@ where Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()), spec, None, + Some(kzg), ); self.execution_layer = Some(mock.el.clone()); self.mock_execution_layer = Some(mock); @@ -477,6 +487,11 @@ where let deneb_time = spec.deneb_fork_epoch.map(|epoch| { HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() }); + let trusted_setup: TrustedSetup = + serde_json::from_reader(eth2_network_config::TRUSTED_SETUP) + .map_err(|e| format!("Unable to read trusted setup file: {}", e)) + .expect("should have trusted setup"); + let kzg = Kzg::new_from_trusted_setup(trusted_setup).expect("should create kzg"); let mock_el = MockExecutionLayer::new( self.runtime.task_executor.clone(), DEFAULT_TERMINAL_BLOCK, @@ -486,6 +501,7 @@ where Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()), spec.clone(), Some(builder_url.clone()), + Some(kzg), ) .move_to_terminal_block(); @@ -755,7 +771,7 @@ where &self, mut state: BeaconState, slot: Slot, - ) -> (SignedBeaconBlock, BeaconState) { + ) -> (BlockContentsTuple>, BeaconState) { assert_ne!(slot, 0, "can't produce a block at slot 0"); assert!(slot >= state.slot()); @@ -795,7 +811,37 @@ where &self.spec, ); - (signed_block, state) + let block_contents: BlockContentsTuple> = match &signed_block { + SignedBeaconBlock::Base(_) + | SignedBeaconBlock::Altair(_) + | SignedBeaconBlock::Merge(_) + | SignedBeaconBlock::Capella(_) => (signed_block, None), + SignedBeaconBlock::Deneb(_) => { + if let Some(blobs) = self + .chain + .proposal_blob_cache + .pop(&signed_block.canonical_root()) + { + let signed_blobs = Vec::from(blobs) + .into_iter() + .map(|blob| { + blob.sign( + &self.validator_keypairs[proposer_index].sk, + &state.fork(), + state.genesis_validators_root(), + &self.spec, + ) + }) + .collect::>() + .into(); + (signed_block, Some(signed_blobs)) + } else { + (signed_block, None) + } + } + }; + + (block_contents, state) } /// Useful for the `per_block_processing` tests. Creates a block, and returns the state after @@ -1663,18 +1709,18 @@ where (deposits, state) } - pub async fn process_block( + pub async fn process_block>>( &self, slot: Slot, block_root: Hash256, - block: SignedBeaconBlock, + block: B, ) -> Result> { self.set_current_slot(slot); let block_hash: SignedBeaconBlockHash = self .chain .process_block( block_root, - Arc::new(block), + block.into(), CountUnrealized::True, NotifyExecutionLayer::Yes, ) @@ -1685,15 +1731,16 @@ where Ok(block_hash) } - pub async fn process_block_result( + pub async fn process_block_result>>( &self, - block: SignedBeaconBlock, + block: B, ) -> Result> { + let wrapped_block = block.into(); let block_hash: SignedBeaconBlockHash = self .chain .process_block( - block.canonical_root(), - Arc::new(block), + wrapped_block.canonical_root(), + wrapped_block, CountUnrealized::True, NotifyExecutionLayer::Yes, ) @@ -1759,11 +1806,18 @@ where &self, slot: Slot, state: BeaconState, - ) -> Result<(SignedBeaconBlockHash, SignedBeaconBlock, BeaconState), BlockError> { + ) -> Result< + ( + SignedBeaconBlockHash, + BlockContentsTuple>, + BeaconState, + ), + BlockError, + > { self.set_current_slot(slot); let (block, new_state) = self.make_block(state, slot).await; let block_hash = self - .process_block(slot, block.canonical_root(), block.clone()) + .process_block(slot, block.0.canonical_root(), block.clone()) .await?; Ok((block_hash, block, new_state)) } @@ -1819,7 +1873,7 @@ where sync_committee_strategy: SyncCommitteeStrategy, ) -> Result<(SignedBeaconBlockHash, BeaconState), BlockError> { let (block_hash, block, state) = self.add_block_at_slot(slot, state).await?; - self.attest_block(&state, state_root, block_hash, &block, validators); + self.attest_block(&state, state_root, block_hash, &block.0, validators); if sync_committee_strategy == SyncCommitteeStrategy::AllValidators && state.current_sync_committee().is_ok() @@ -2047,7 +2101,7 @@ where state: BeaconState, slot: Slot, _block_strategy: BlockStrategy, - ) -> (SignedBeaconBlock, BeaconState) { + ) -> (BlockContentsTuple>, BeaconState) { self.make_block(state, slot).await } diff --git a/beacon_node/beacon_chain/tests/block_verification.rs b/beacon_node/beacon_chain/tests/block_verification.rs index 88364d6ff..4b6d5b241 100644 --- a/beacon_node/beacon_chain/tests/block_verification.rs +++ b/beacon_node/beacon_chain/tests/block_verification.rs @@ -1025,8 +1025,8 @@ async fn verify_block_for_gossip_slashing_detection() { harness.advance_slot(); let state = harness.get_current_state(); - let (block1, _) = harness.make_block(state.clone(), Slot::new(1)).await; - let (block2, _) = harness.make_block(state, Slot::new(1)).await; + let ((block1, _), _) = harness.make_block(state.clone(), Slot::new(1)).await; + let ((block2, _), _) = harness.make_block(state, Slot::new(1)).await; let verified_block = harness .chain @@ -1065,7 +1065,7 @@ async fn verify_block_for_gossip_doppelganger_detection() { let harness = get_harness(VALIDATOR_COUNT); let state = harness.get_current_state(); - let (block, _) = harness.make_block(state.clone(), Slot::new(1)).await; + let ((block, _), _) = harness.make_block(state.clone(), Slot::new(1)).await; let verified_block = harness .chain @@ -1152,7 +1152,7 @@ async fn add_base_block_to_altair_chain() { // Produce an Altair block. let state = harness.get_current_state(); let slot = harness.get_current_slot(); - let (altair_signed_block, _) = harness.make_block(state.clone(), slot).await; + let ((altair_signed_block, _), _) = harness.make_block(state.clone(), slot).await; let altair_block = &altair_signed_block .as_altair() .expect("test expects an altair block") @@ -1289,7 +1289,7 @@ async fn add_altair_block_to_base_chain() { // Produce an altair block. let state = harness.get_current_state(); let slot = harness.get_current_slot(); - let (base_signed_block, _) = harness.make_block(state.clone(), slot).await; + let ((base_signed_block, _), _) = harness.make_block(state.clone(), slot).await; let base_block = &base_signed_block .as_base() .expect("test expects a base block") diff --git a/beacon_node/beacon_chain/tests/payload_invalidation.rs b/beacon_node/beacon_chain/tests/payload_invalidation.rs index dbb2ebfae..e85b021f5 100644 --- a/beacon_node/beacon_chain/tests/payload_invalidation.rs +++ b/beacon_node/beacon_chain/tests/payload_invalidation.rs @@ -223,7 +223,7 @@ impl InvalidPayloadRig { let head = self.harness.chain.head_snapshot(); let state = head.beacon_state.clone_with_only_committee_caches(); let slot = slot_override.unwrap_or(state.slot() + 1); - let (block, post_state) = self.harness.make_block(state, slot).await; + let ((block, _), post_state) = self.harness.make_block(state, slot).await; let block_root = block.canonical_root(); let set_new_payload = |payload: Payload| match payload { @@ -691,7 +691,8 @@ async fn invalidates_all_descendants() { .state_at_slot(fork_parent_slot, StateSkipConfig::WithStateRoots) .unwrap(); assert_eq!(fork_parent_state.slot(), fork_parent_slot); - let (fork_block, _fork_post_state) = rig.harness.make_block(fork_parent_state, fork_slot).await; + let ((fork_block, _), _fork_post_state) = + rig.harness.make_block(fork_parent_state, fork_slot).await; let fork_block_root = rig .harness .chain @@ -789,7 +790,8 @@ async fn switches_heads() { .state_at_slot(fork_parent_slot, StateSkipConfig::WithStateRoots) .unwrap(); assert_eq!(fork_parent_state.slot(), fork_parent_slot); - let (fork_block, _fork_post_state) = rig.harness.make_block(fork_parent_state, fork_slot).await; + let ((fork_block, _), _fork_post_state) = + rig.harness.make_block(fork_parent_state, fork_slot).await; let fork_parent_root = fork_block.parent_root(); let fork_block_root = rig .harness @@ -1033,8 +1035,8 @@ async fn invalid_parent() { // Produce another block atop the parent, but don't import yet. let slot = parent_block.slot() + 1; rig.harness.set_current_slot(slot); - let (block, state) = rig.harness.make_block(parent_state, slot).await; - let block = Arc::new(block); + let (block_tuple, state) = rig.harness.make_block(parent_state, slot).await; + let block = Arc::new(block_tuple.0); let block_root = block.canonical_root(); assert_eq!(block.parent_root(), parent_root); @@ -1850,8 +1852,8 @@ impl InvalidHeadSetup { .chain .state_at_slot(slot - 1, StateSkipConfig::WithStateRoots) .unwrap(); - let (fork_block, _) = rig.harness.make_block(parent_state, slot).await; - opt_fork_block = Some(Arc::new(fork_block)); + let (fork_block_tuple, _) = rig.harness.make_block(parent_state, slot).await; + opt_fork_block = Some(Arc::new(fork_block_tuple.0)); } else { // Skipped slot. }; diff --git a/beacon_node/beacon_chain/tests/store_tests.rs b/beacon_node/beacon_chain/tests/store_tests.rs index 33cb58fa7..239ae1806 100644 --- a/beacon_node/beacon_chain/tests/store_tests.rs +++ b/beacon_node/beacon_chain/tests/store_tests.rs @@ -2022,7 +2022,7 @@ async fn garbage_collect_temp_states_from_failed_block() { let genesis_state = harness.get_current_state(); let block_slot = Slot::new(2 * slots_per_epoch); - let (signed_block, state) = harness.make_block(genesis_state, block_slot).await; + let ((signed_block, _), state) = harness.make_block(genesis_state, block_slot).await; let (mut block, _) = signed_block.deconstruct(); @@ -2422,7 +2422,7 @@ async fn revert_minority_fork_on_resume() { harness1.process_attestations(attestations.clone()); harness2.process_attestations(attestations); - let (block, new_state) = harness1.make_block(state, slot).await; + let ((block, _), new_state) = harness1.make_block(state, slot).await; harness1 .process_block(slot, block.canonical_root(), block.clone()) @@ -2463,7 +2463,7 @@ async fn revert_minority_fork_on_resume() { harness2.process_attestations(attestations); // Minority chain block (no attesters). - let (block1, new_state1) = harness1.make_block(state1, slot).await; + let ((block1, _), new_state1) = harness1.make_block(state1, slot).await; harness1 .process_block(slot, block1.canonical_root(), block1) .await @@ -2471,7 +2471,7 @@ async fn revert_minority_fork_on_resume() { state1 = new_state1; // Majority chain block (all attesters). - let (block2, new_state2) = harness2.make_block(state2, slot).await; + let ((block2, _), new_state2) = harness2.make_block(state2, slot).await; harness2 .process_block(slot, block2.canonical_root(), block2.clone()) .await diff --git a/beacon_node/execution_layer/Cargo.toml b/beacon_node/execution_layer/Cargo.toml index 1b687a8b6..d001a482d 100644 --- a/beacon_node/execution_layer/Cargo.toml +++ b/beacon_node/execution_layer/Cargo.toml @@ -25,6 +25,7 @@ hex = "0.4.2" eth2_ssz = "0.4.1" eth2_ssz_types = "0.2.2" eth2 = { path = "../../common/eth2" } +kzg = { path = "../../crypto/kzg" } state_processing = { path = "../../consensus/state_processing" } superstruct = "0.6.0" lru = "0.7.1" diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 02d9e8149..cb09d3a0b 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -16,12 +16,14 @@ use serde::{Deserialize, Serialize}; use std::convert::TryFrom; use strum::IntoStaticStr; use superstruct::superstruct; +use types::beacon_block_body::KzgCommitments; +use types::blob_sidecar::Blobs; pub use types::{ Address, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadHeader, ExecutionPayloadRef, FixedVector, ForkName, Hash256, Transactions, Uint256, VariableList, Withdrawal, Withdrawals, }; -use types::{ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadMerge}; +use types::{ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadMerge, KzgProofs}; pub mod auth; pub mod http; @@ -377,6 +379,8 @@ pub struct GetPayloadResponse { #[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))] pub execution_payload: ExecutionPayloadDeneb, pub block_value: Uint256, + #[superstruct(only(Deneb))] + pub blobs_bundle: BlobsBundleV1, } impl<'a, T: EthSpec> From> for ExecutionPayloadRef<'a, T> { @@ -395,20 +399,25 @@ impl From> for ExecutionPayload { } } -impl From> for (ExecutionPayload, Uint256) { +impl From> + for (ExecutionPayload, Uint256, Option>) +{ fn from(response: GetPayloadResponse) -> Self { match response { GetPayloadResponse::Merge(inner) => ( ExecutionPayload::Merge(inner.execution_payload), inner.block_value, + None, ), GetPayloadResponse::Capella(inner) => ( ExecutionPayload::Capella(inner.execution_payload), inner.block_value, + None, ), GetPayloadResponse::Deneb(inner) => ( ExecutionPayload::Deneb(inner.execution_payload), inner.block_value, + Some(inner.blobs_bundle), ), } } @@ -513,6 +522,13 @@ impl ExecutionPayloadBodyV1 { } } +#[derive(Clone, Default, Debug, PartialEq)] +pub struct BlobsBundleV1 { + pub commitments: KzgCommitments, + pub proofs: KzgProofs, + pub blobs: Blobs, +} + #[derive(Clone, Copy, Debug)] pub struct EngineCapabilities { pub new_payload_v1: bool, diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index b47779407..137ba5318 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -40,9 +40,6 @@ pub const ENGINE_GET_PAYLOAD_V2: &str = "engine_getPayloadV2"; pub const ENGINE_GET_PAYLOAD_V3: &str = "engine_getPayloadV3"; pub const ENGINE_GET_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(2); -pub const ENGINE_GET_BLOBS_BUNDLE_V1: &str = "engine_getBlobsBundleV1"; -pub const ENGINE_GET_BLOBS_BUNDLE_TIMEOUT: Duration = Duration::from_secs(2); - pub const ENGINE_FORKCHOICE_UPDATED_V1: &str = "engine_forkchoiceUpdatedV1"; pub const ENGINE_FORKCHOICE_UPDATED_V2: &str = "engine_forkchoiceUpdatedV2"; pub const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8); @@ -927,23 +924,6 @@ impl HttpJsonRpc { } } - pub async fn get_blobs_bundle_v1( - &self, - payload_id: PayloadId, - ) -> Result, Error> { - let params = json!([JsonPayloadIdRequest::from(payload_id)]); - - let response: JsonBlobsBundle = self - .rpc_request( - ENGINE_GET_BLOBS_BUNDLE_V1, - params, - ENGINE_GET_BLOBS_BUNDLE_TIMEOUT, - ) - .await?; - - Ok(response) - } - pub async fn forkchoice_updated_v1( &self, forkchoice_state: ForkchoiceState, 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 d7d9aae29..6f35b5285 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -291,6 +291,8 @@ pub struct JsonGetPayloadResponse { pub execution_payload: JsonExecutionPayloadV3, #[serde(with = "eth2_serde_utils::u256_hex_be")] pub block_value: Uint256, + #[superstruct(only(V3))] + pub blobs_bundle: JsonBlobsBundleV1, } impl From> for GetPayloadResponse { @@ -312,6 +314,7 @@ impl From> for GetPayloadResponse { GetPayloadResponse::Deneb(GetPayloadResponseDeneb { execution_payload: response.execution_payload.into(), block_value: response.block_value, + blobs_bundle: response.blobs_bundle.into(), }) } } @@ -409,12 +412,31 @@ impl From for PayloadAttributes { } #[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(bound = "T: EthSpec", rename_all = "camelCase")] -pub struct JsonBlobsBundle { - pub block_hash: ExecutionBlockHash, - pub kzgs: KzgCommitments, +#[serde(bound = "E: EthSpec", rename_all = "camelCase")] +pub struct JsonBlobsBundleV1 { + pub commitments: KzgCommitments, + pub proofs: KzgProofs, #[serde(with = "ssz_types::serde_utils::list_of_hex_fixed_vec")] - pub blobs: Blobs, + pub blobs: Blobs, +} + +impl From> for JsonBlobsBundleV1 { + fn from(blobs_bundle: BlobsBundleV1) -> Self { + Self { + commitments: blobs_bundle.commitments, + proofs: blobs_bundle.proofs, + blobs: blobs_bundle.blobs, + } + } +} +impl From> for BlobsBundleV1 { + fn from(json_blobs_bundle: JsonBlobsBundleV1) -> Self { + Self { + commitments: json_blobs_bundle.commitments, + proofs: json_blobs_bundle.proofs, + blobs: json_blobs_bundle.blobs, + } + } } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index adf5e059b..0e1fddfad 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -45,12 +45,12 @@ use types::beacon_block_body::KzgCommitments; use types::blob_sidecar::Blobs; use types::consts::deneb::BLOB_TX_TYPE; use types::transaction::{AccessTuple, BlobTransaction, EcdsaSignature, SignedBlobTransaction}; -use types::Withdrawals; use types::{AbstractExecPayload, BeaconStateError, ExecPayload, VersionedHash}; use types::{ BlindedPayload, BlockType, ChainSpec, Epoch, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadMerge, ForkName, }; +use types::{KzgProofs, Withdrawals}; use types::{ ProposerPreparationData, PublicKeyBytes, Signature, SignedBeaconBlock, Slot, Transaction, Uint256, @@ -141,22 +141,53 @@ pub enum BlockProposalContents> { block_value: Uint256, kzg_commitments: KzgCommitments, blobs: Blobs, + proofs: KzgProofs, }, } +impl> From> + for BlockProposalContents +{ + fn from(response: GetPayloadResponse) -> Self { + let (execution_payload, block_value, maybe_bundle) = response.into(); + match maybe_bundle { + Some(bundle) => Self::PayloadAndBlobs { + payload: execution_payload.into(), + block_value, + kzg_commitments: bundle.commitments, + blobs: bundle.blobs, + proofs: bundle.proofs, + }, + None => Self::Payload { + payload: execution_payload.into(), + block_value, + }, + } + } +} + +#[allow(clippy::type_complexity)] impl> BlockProposalContents { - pub fn deconstruct(self) -> (Payload, Option>, Option>) { + pub fn deconstruct( + self, + ) -> ( + Payload, + Option>, + Option>, + Option>, + ) { match self { Self::Payload { payload, block_value: _, - } => (payload, None, None), + } => (payload, None, None, None), Self::PayloadAndBlobs { payload, block_value: _, kzg_commitments, blobs, - } => (payload, Some(kzg_commitments), Some(blobs)), + proofs, + } => (payload, Some(kzg_commitments), Some(blobs), Some(proofs)), } } @@ -171,6 +202,7 @@ impl> BlockProposalContents payload, } } @@ -185,6 +217,7 @@ impl> BlockProposalContents payload, } } @@ -199,6 +232,7 @@ impl> BlockProposalContents block_value, } } @@ -215,6 +249,7 @@ impl> BlockProposalContents ExecutionLayer { } }; - let blob_fut = async { - match current_fork { - ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => { - None - } - ForkName::Deneb => { - debug!( - self.log(), - "Issuing engine_getBlobsBundle"; - "suggested_fee_recipient" => ?payload_attributes.suggested_fee_recipient(), - "prev_randao" => ?payload_attributes.prev_randao(), - "timestamp" => payload_attributes.timestamp(), - "parent_hash" => ?parent_hash, - ); - Some(engine.api.get_blobs_bundle_v1::(payload_id).await) - } - } - }; - let payload_fut = async { + let payload_response = async { debug!( self.log(), "Issuing engine_getPayload"; @@ -1144,45 +1161,30 @@ impl ExecutionLayer { "parent_hash" => ?parent_hash, ); engine.api.get_payload::(current_fork, payload_id).await - }; - let (blob, payload_response) = tokio::join!(blob_fut, payload_fut); - let (execution_payload, block_value) = payload_response.map(|payload_response| { - if payload_response.execution_payload_ref().fee_recipient() != payload_attributes.suggested_fee_recipient() { - error!( - self.log(), - "Inconsistent fee recipient"; - "msg" => "The fee recipient returned from the Execution Engine differs \ - from the suggested_fee_recipient set on the beacon node. This could \ - indicate that fees are being diverted to another address. Please \ - ensure that the value of suggested_fee_recipient is set correctly and \ - that the Execution Engine is trusted.", - "fee_recipient" => ?payload_response.execution_payload_ref().fee_recipient(), - "suggested_fee_recipient" => ?payload_attributes.suggested_fee_recipient(), - ); - } - if f(self, payload_response.execution_payload_ref()).is_some() { - warn!( - self.log(), - "Duplicate payload cached, this might indicate redundant proposal \ - attempts." - ); - } - payload_response.into() - })?; - if let Some(blob) = blob.transpose()? { - // FIXME(sean) cache blobs - Ok(BlockProposalContents::PayloadAndBlobs { - payload: execution_payload.into(), - block_value, - blobs: blob.blobs, - kzg_commitments: blob.kzgs, - }) - } else { - Ok(BlockProposalContents::Payload { - payload: execution_payload.into(), - block_value, - }) + }.await?; + + if payload_response.execution_payload_ref().fee_recipient() != payload_attributes.suggested_fee_recipient() { + error!( + self.log(), + "Inconsistent fee recipient"; + "msg" => "The fee recipient returned from the Execution Engine differs \ + from the suggested_fee_recipient set on the beacon node. This could \ + indicate that fees are being diverted to another address. Please \ + ensure that the value of suggested_fee_recipient is set correctly and \ + that the Execution Engine is trusted.", + "fee_recipient" => ?payload_response.execution_payload_ref().fee_recipient(), + "suggested_fee_recipient" => ?payload_attributes.suggested_fee_recipient(), + ); } + if f(self, payload_response.execution_payload_ref()).is_some() { + warn!( + self.log(), + "Duplicate payload cached, this might indicate redundant proposal \ + attempts." + ); + } + + Ok(payload_response.into()) }) .await .map_err(Box::new) 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 e5a5c70d7..773c3fe9d 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 @@ -6,15 +6,21 @@ use crate::{ }, ExecutionBlock, PayloadAttributes, PayloadId, PayloadStatusV1, PayloadStatusV1Status, }, - ExecutionBlockWithTransactions, + BlobsBundleV1, ExecutionBlockWithTransactions, }; +use kzg::{Kzg, BYTES_PER_BLOB, BYTES_PER_FIELD_ELEMENT, FIELD_ELEMENTS_PER_BLOB}; +use rand::RngCore; use serde::{Deserialize, Serialize}; +use ssz::Encode; use std::collections::HashMap; +use std::sync::Arc; use tree_hash::TreeHash; use tree_hash_derive::TreeHash; +use types::transaction::{BlobTransaction, EcdsaSignature, SignedBlobTransaction}; use types::{ - EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadMerge, ForkName, Hash256, Uint256, + Blob, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, + ExecutionPayloadDeneb, ExecutionPayloadMerge, ForkName, Hash256, Transaction, Transactions, + Uint256, }; const GAS_LIMIT: u64 = 16384; @@ -119,6 +125,11 @@ pub struct ExecutionBlockGenerator { */ pub shanghai_time: Option, // withdrawals pub deneb_time: Option, // 4844 + /* + * deneb stuff + */ + pub blobs_bundles: HashMap>, + pub kzg: Option>, } impl ExecutionBlockGenerator { @@ -128,6 +139,7 @@ impl ExecutionBlockGenerator { terminal_block_hash: ExecutionBlockHash, shanghai_time: Option, deneb_time: Option, + kzg: Option, ) -> Self { let mut gen = Self { head_block: <_>::default(), @@ -142,6 +154,8 @@ impl ExecutionBlockGenerator { payload_ids: <_>::default(), shanghai_time, deneb_time, + blobs_bundles: <_>::default(), + kzg: kzg.map(Arc::new), }; gen.insert_pow_block(0).unwrap(); @@ -394,6 +408,11 @@ impl ExecutionBlockGenerator { self.payload_ids.get(id).cloned() } + pub fn get_blobs_bundle(&mut self, id: &PayloadId) -> Option> { + // remove it to free memory + self.blobs_bundles.remove(id) + } + pub fn new_payload(&mut self, payload: ExecutionPayload) -> PayloadStatusV1 { let parent = if let Some(parent) = self.blocks.get(&payload.parent_hash()) { parent @@ -561,6 +580,22 @@ impl ExecutionBlockGenerator { } }; + match execution_payload.fork_name() { + ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => {} + ForkName::Deneb => { + // get random number between 0 and Max Blobs + let num_blobs = rand::random::() % T::max_blobs_per_block(); + let (bundle, transactions) = self.generate_random_blobs(num_blobs)?; + for tx in Vec::from(transactions) { + execution_payload + .transactions_mut() + .push(tx) + .map_err(|_| "transactions are full".to_string())?; + } + self.blobs_bundles.insert(id, bundle); + } + } + *execution_payload.block_hash_mut() = ExecutionBlockHash::from_root(execution_payload.tree_hash_root()); @@ -590,6 +625,88 @@ impl ExecutionBlockGenerator { payload_id: id.map(Into::into), }) } + + fn generate_random_blobs( + &self, + n_blobs: usize, + ) -> Result<(BlobsBundleV1, Transactions), String> { + let mut bundle = BlobsBundleV1::::default(); + let mut transactions = vec![]; + for blob_index in 0..n_blobs { + // fill a vector with random bytes + let mut blob_bytes = [0u8; BYTES_PER_BLOB]; + rand::thread_rng().fill_bytes(&mut blob_bytes); + // Ensure that the blob is canonical by ensuring that + // each field element contained in the blob is < BLS_MODULUS + for i in 0..FIELD_ELEMENTS_PER_BLOB { + blob_bytes[i * BYTES_PER_FIELD_ELEMENT + BYTES_PER_FIELD_ELEMENT - 1] = 0; + } + + let blob = Blob::::new(Vec::from(blob_bytes)) + .map_err(|e| format!("error constructing random blob: {:?}", e))?; + + let commitment = self + .kzg + .as_ref() + .ok_or("kzg not initialized")? + .blob_to_kzg_commitment(blob_bytes.into()) + .map_err(|e| format!("error computing kzg commitment: {:?}", e))?; + + let proof = self + .kzg + .as_ref() + .ok_or("kzg not initialized")? + .compute_blob_kzg_proof(blob_bytes.into(), commitment) + .map_err(|e| format!("error computing kzg proof: {:?}", e))?; + + let versioned_hash = commitment.calculate_versioned_hash(); + + let blob_transaction = BlobTransaction { + chain_id: Default::default(), + nonce: 0, + max_priority_fee_per_gas: Default::default(), + max_fee_per_gas: Default::default(), + gas: 100000, + to: None, + value: Default::default(), + data: Default::default(), + access_list: Default::default(), + max_fee_per_data_gas: Default::default(), + versioned_hashes: vec![versioned_hash].into(), + }; + let bad_signature = EcdsaSignature { + y_parity: false, + r: Uint256::from(0), + s: Uint256::from(0), + }; + let signed_blob_transaction = SignedBlobTransaction { + message: blob_transaction, + signature: bad_signature, + }; + // calculate transaction bytes + let tx_bytes = [0x05u8] + .into_iter() + .chain(signed_blob_transaction.as_ssz_bytes().into_iter()) + .collect::>(); + let tx = Transaction::::from(tx_bytes); + + transactions.push(tx); + bundle + .blobs + .push(blob) + .map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?; + bundle + .commitments + .push(commitment) + .map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?; + bundle + .proofs + .push(proof) + .map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?; + } + + Ok((bundle, transactions.into())) + } } fn payload_id_from_u64(n: u64) -> PayloadId { @@ -650,6 +767,7 @@ mod test { ExecutionBlockHash::zero(), None, None, + None, ); for i in 0..=TERMINAL_BLOCK { 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 aae1a0b89..6122f28dc 100644 --- a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs +++ b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs @@ -224,6 +224,8 @@ pub async fn handle_rpc( ) })?; + let maybe_blobs = ctx.execution_block_generator.write().get_blobs_bundle(&id); + // validate method called correctly according to shanghai fork time if ctx .execution_block_generator @@ -291,6 +293,12 @@ pub async fn handle_rpc( serde_json::to_value(JsonGetPayloadResponseV3 { execution_payload, block_value: DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI.into(), + blobs_bundle: maybe_blobs + .ok_or(( + "No blobs returned despite V3 Payload".to_string(), + GENERIC_ERROR_CODE, + ))? + .into(), }) .unwrap() } @@ -324,7 +332,7 @@ pub async fn handle_rpc( .map(|opt| opt.map(JsonPayloadAttributes::V1)) .transpose() } - ForkName::Capella => { + ForkName::Capella | ForkName::Deneb => { get_param::>(params, 1) .map(|opt| opt.map(JsonPayloadAttributes::V2)) .transpose() diff --git a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs index 44fc2a5ec..0c6f5ce66 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs @@ -5,6 +5,7 @@ use crate::{ }, Config, *, }; +use kzg::Kzg; use sensitive_url::SensitiveUrl; use task_executor::TaskExecutor; use tempfile::NamedTempFile; @@ -33,6 +34,7 @@ impl MockExecutionLayer { Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()), spec, None, + None, ) } @@ -46,6 +48,7 @@ impl MockExecutionLayer { jwt_key: Option, spec: ChainSpec, builder_url: Option, + kzg: Option, ) -> Self { let handle = executor.handle().unwrap(); @@ -58,6 +61,7 @@ impl MockExecutionLayer { spec.terminal_block_hash, shanghai_time, deneb_time, + kzg, ); let url = SensitiveUrl::parse(&server.url()).unwrap(); diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index 60f5bf341..ef728722d 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -8,6 +8,7 @@ use bytes::Bytes; use environment::null_logger; use execution_block_generator::PoWBlock; use handle_rpc::handle_rpc; +use kzg::Kzg; use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; use serde::{Deserialize, Serialize}; use serde_json::json; @@ -96,10 +97,15 @@ impl MockServer { ExecutionBlockHash::zero(), None, // FIXME(capella): should this be the default? None, // FIXME(deneb): should this be the default? + None, // FIXME(deneb): should this be the default? ) } - pub fn new_with_config(handle: &runtime::Handle, config: MockExecutionConfig) -> Self { + pub fn new_with_config( + handle: &runtime::Handle, + config: MockExecutionConfig, + kzg: Option, + ) -> Self { let MockExecutionConfig { jwt_key, terminal_difficulty, @@ -117,6 +123,7 @@ impl MockServer { terminal_block_hash, shanghai_time, deneb_time, + kzg, ); let ctx: Arc> = Arc::new(Context { @@ -168,6 +175,7 @@ impl MockServer { *self.ctx.engine_capabilities.write() = engine_capabilities; } + #[allow(clippy::too_many_arguments)] pub fn new( handle: &runtime::Handle, jwt_key: JwtKey, @@ -176,6 +184,7 @@ impl MockServer { terminal_block_hash: ExecutionBlockHash, shanghai_time: Option, deneb_time: Option, + kzg: Option, ) -> Self { Self::new_with_config( handle, @@ -188,6 +197,7 @@ impl MockServer { shanghai_time, deneb_time, }, + kzg, ) } diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index b3e5bf39c..d12274308 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -480,7 +480,7 @@ pub async fn proposer_boost_re_org_test( // Produce block B and process it halfway through the slot. let (block_b, mut state_b) = harness.make_block(state_a.clone(), slot_b).await; - let block_b_root = block_b.canonical_root(); + let block_b_root = block_b.0.canonical_root(); let obs_time = slot_clock.start_of(slot_b).unwrap() + slot_clock.slot_duration() / 2; slot_clock.set_current_time(obs_time); @@ -573,8 +573,18 @@ pub async fn proposer_boost_re_org_test( // Check the fork choice updates that were sent. let forkchoice_updates = forkchoice_updates.lock(); - let block_a_exec_hash = block_a.message().execution_payload().unwrap().block_hash(); - let block_b_exec_hash = block_b.message().execution_payload().unwrap().block_hash(); + let block_a_exec_hash = block_a + .0 + .message() + .execution_payload() + .unwrap() + .block_hash(); + let block_b_exec_hash = block_b + .0 + .message() + .execution_payload() + .unwrap() + .block_hash(); let block_c_timestamp = block_c.message().execution_payload().unwrap().timestamp(); @@ -679,7 +689,7 @@ pub async fn fork_choice_before_proposal() { let state_a = harness.get_current_state(); let (block_b, state_b) = harness.make_block(state_a.clone(), slot_b).await; let block_root_b = harness - .process_block(slot_b, block_b.canonical_root(), block_b) + .process_block(slot_b, block_b.0.canonical_root(), block_b) .await .unwrap(); @@ -694,7 +704,7 @@ pub async fn fork_choice_before_proposal() { let (block_c, state_c) = harness.make_block(state_a, slot_c).await; let block_root_c = harness - .process_block(slot_c, block_c.canonical_root(), block_c.clone()) + .process_block(slot_c, block_c.0.canonical_root(), block_c.clone()) .await .unwrap(); diff --git a/beacon_node/network/src/beacon_processor/tests.rs b/beacon_node/network/src/beacon_processor/tests.rs index 30e7e358c..0f434fdc3 100644 --- a/beacon_node/network/src/beacon_processor/tests.rs +++ b/beacon_node/network/src/beacon_processor/tests.rs @@ -107,7 +107,7 @@ impl TestRig { "precondition: current slot is one after head" ); - let (next_block, next_state) = harness + let (next_block_tuple, next_state) = harness .make_block(head.beacon_state.clone(), harness.chain.slot().unwrap()) .await; @@ -133,9 +133,9 @@ impl TestRig { .get_unaggregated_attestations( &AttestationStrategy::AllValidators, &next_state, - next_block.state_root(), - next_block.canonical_root(), - next_block.slot(), + next_block_tuple.0.state_root(), + next_block_tuple.0.canonical_root(), + next_block_tuple.0.slot(), ) .into_iter() .flatten() @@ -145,9 +145,9 @@ impl TestRig { .make_attestations( &harness.get_all_validators(), &next_state, - next_block.state_root(), - next_block.canonical_root().into(), - next_block.slot(), + next_block_tuple.0.state_root(), + next_block_tuple.0.canonical_root().into(), + next_block_tuple.0.slot(), ) .into_iter() .filter_map(|(_, aggregate_opt)| aggregate_opt) @@ -209,7 +209,7 @@ impl TestRig { Self { chain, - next_block: Arc::new(next_block), + next_block: Arc::new(next_block_tuple.0), attestations, next_block_attestations, next_block_aggregate_attestations, diff --git a/consensus/fork_choice/tests/tests.rs b/consensus/fork_choice/tests/tests.rs index 82bf642f1..e596fb2e1 100644 --- a/consensus/fork_choice/tests/tests.rs +++ b/consensus/fork_choice/tests/tests.rs @@ -179,15 +179,15 @@ impl ForkChoiceTest { let slot = self.harness.get_current_slot(); let (block, state_) = self.harness.make_block(state, slot).await; state = state_; - if !predicate(block.message(), &state) { + if !predicate(block.0.message(), &state) { break; } if let Ok(block_hash) = self.harness.process_block_result(block.clone()).await { self.harness.attest_block( &state, - block.state_root(), + block.0.state_root(), block_hash, - &block, + &block.0, &validators, ); self.harness.advance_slot(); @@ -273,8 +273,8 @@ impl ForkChoiceTest { ) .unwrap(); let slot = self.harness.get_current_slot(); - let (mut signed_block, mut state) = self.harness.make_block(state, slot).await; - func(&mut signed_block, &mut state); + let (mut block_tuple, mut state) = self.harness.make_block(state, slot).await; + func(&mut block_tuple.0, &mut state); let current_slot = self.harness.get_current_slot(); self.harness .chain @@ -282,8 +282,8 @@ impl ForkChoiceTest { .fork_choice_write_lock() .on_block( current_slot, - signed_block.message(), - signed_block.canonical_root(), + block_tuple.0.message(), + block_tuple.0.canonical_root(), Duration::from_secs(0), &state, PayloadVerificationStatus::Verified, @@ -315,8 +315,8 @@ impl ForkChoiceTest { ) .unwrap(); let slot = self.harness.get_current_slot(); - let (mut signed_block, mut state) = self.harness.make_block(state, slot).await; - mutation_func(&mut signed_block, &mut state); + let (mut block_tuple, mut state) = self.harness.make_block(state, slot).await; + mutation_func(&mut block_tuple.0, &mut state); let current_slot = self.harness.get_current_slot(); let err = self .harness @@ -325,8 +325,8 @@ impl ForkChoiceTest { .fork_choice_write_lock() .on_block( current_slot, - signed_block.message(), - signed_block.canonical_root(), + block_tuple.0.message(), + block_tuple.0.canonical_root(), Duration::from_secs(0), &state, PayloadVerificationStatus::Verified, diff --git a/consensus/types/src/blob_sidecar.rs b/consensus/types/src/blob_sidecar.rs index fde54bc72..f0a1f0ee4 100644 --- a/consensus/types/src/blob_sidecar.rs +++ b/consensus/types/src/blob_sidecar.rs @@ -1,5 +1,6 @@ use crate::test_utils::TestRandom; -use crate::{Blob, EthSpec, Hash256, SignedRoot, Slot}; +use crate::{Blob, ChainSpec, Domain, EthSpec, Fork, Hash256, SignedBlobSidecar, SignedRoot, Slot}; +use bls::SecretKey; use derivative::Derivative; use kzg::{KzgCommitment, KzgProof}; use serde_derive::{Deserialize, Serialize}; @@ -72,7 +73,7 @@ impl Ord for BlobSidecar { } pub type BlobSidecarList = VariableList>, ::MaxBlobsPerBlock>; -pub type Blobs = VariableList, ::MaxExtraDataBytes>; +pub type Blobs = VariableList, ::MaxBlobsPerBlock>; impl SignedRoot for BlobSidecar {} @@ -93,4 +94,28 @@ impl BlobSidecar { // Fixed part Self::empty().as_ssz_bytes().len() } + + // this is mostly not used except for in testing + pub fn sign( + self: Arc, + secret_key: &SecretKey, + fork: &Fork, + genesis_validators_root: Hash256, + spec: &ChainSpec, + ) -> SignedBlobSidecar { + let signing_epoch = self.slot.epoch(T::slots_per_epoch()); + let domain = spec.get_domain( + signing_epoch, + Domain::BlobSidecar, + fork, + genesis_validators_root, + ); + let message = self.signing_root(domain); + let signature = secret_key.sign(message); + + SignedBlobSidecar { + message: self, + signature, + } + } } diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index d38d7f368..617cbcaf0 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -204,6 +204,7 @@ pub type Address = H160; pub type ForkVersion = [u8; 4]; pub type BLSFieldElement = Uint256; pub type Blob = FixedVector::BytesPerBlob>; +pub type KzgProofs = VariableList::MaxBlobsPerBlock>; pub type VersionedHash = Hash256; pub type Hash64 = ethereum_types::H64; diff --git a/crypto/kzg/src/kzg_commitment.rs b/crypto/kzg/src/kzg_commitment.rs index 0f2725b75..267f70462 100644 --- a/crypto/kzg/src/kzg_commitment.rs +++ b/crypto/kzg/src/kzg_commitment.rs @@ -1,18 +1,29 @@ use c_kzg::{Bytes48, BYTES_PER_COMMITMENT}; use derivative::Derivative; +use eth2_hashing::hash_fixed; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use ssz_derive::{Decode, Encode}; use std::fmt; use std::fmt::{Debug, Display, Formatter}; use std::str::FromStr; -use tree_hash::{PackedEncoding, TreeHash}; +use tree_hash::{Hash256, PackedEncoding, TreeHash}; + +pub const BLOB_COMMITMENT_VERSION_KZG: u8 = 0x01; #[derive(Derivative, Clone, Copy, Encode, Decode)] #[derivative(PartialEq, Eq, Hash)] #[ssz(struct_behaviour = "transparent")] pub struct KzgCommitment(pub [u8; BYTES_PER_COMMITMENT]); +impl KzgCommitment { + pub fn calculate_versioned_hash(&self) -> Hash256 { + let mut versioned_hash = hash_fixed(&self.0); + versioned_hash[0] = BLOB_COMMITMENT_VERSION_KZG; + Hash256::from_slice(versioned_hash.as_slice()) + } +} + impl From for Bytes48 { fn from(value: KzgCommitment) -> Self { value.0.into() diff --git a/crypto/kzg/src/lib.rs b/crypto/kzg/src/lib.rs index 5379d36ed..b300e2d3b 100644 --- a/crypto/kzg/src/lib.rs +++ b/crypto/kzg/src/lib.rs @@ -20,6 +20,7 @@ pub enum Error { } /// A wrapper over a kzg library that holds the trusted setup parameters. +#[derive(Debug)] pub struct Kzg { trusted_setup: KzgSettings, } diff --git a/testing/node_test_rig/src/lib.rs b/testing/node_test_rig/src/lib.rs index d4fd115be..1b822a322 100644 --- a/testing/node_test_rig/src/lib.rs +++ b/testing/node_test_rig/src/lib.rs @@ -236,7 +236,7 @@ impl LocalExecutionNode { panic!("Failed to write jwt file {}", e); } Self { - server: MockServer::new_with_config(&context.executor.handle().unwrap(), config), + server: MockServer::new_with_config(&context.executor.handle().unwrap(), config, None), datadir, } }