diff --git a/Cargo.lock b/Cargo.lock index 70b774064..b2ab1e28e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2531,6 +2531,7 @@ dependencies = [ "bytes", "environment", "eth2", + "eth2_network_config", "ethereum_serde_utils", "ethereum_ssz", "ethers-core", diff --git a/beacon_node/beacon_chain/src/data_availability_checker/availability_view.rs b/beacon_node/beacon_chain/src/data_availability_checker/availability_view.rs index fea2ee101..f013cf649 100644 --- a/beacon_node/beacon_chain/src/data_availability_checker/availability_view.rs +++ b/beacon_node/beacon_chain/src/data_availability_checker/availability_view.rs @@ -267,9 +267,7 @@ pub mod tests { use crate::test_utils::{generate_rand_block_and_blobs, NumBlobs}; use crate::AvailabilityPendingExecutedBlock; use crate::PayloadVerificationOutcome; - use eth2_network_config::get_trusted_setup; use fork_choice::PayloadVerificationStatus; - use kzg::{Kzg, TrustedSetup}; use rand::rngs::StdRng; use rand::SeedableRng; use state_processing::ConsensusContext; @@ -285,13 +283,9 @@ pub mod tests { ); pub fn pre_setup() -> Setup { - let trusted_setup: TrustedSetup = - serde_json::from_reader(get_trusted_setup::<::Kzg>()).unwrap(); - let kzg = Kzg::new_from_trusted_setup(trusted_setup).unwrap(); - let mut rng = StdRng::seed_from_u64(0xDEADBEEF0BAD5EEDu64); let (block, blobs_vec) = - generate_rand_block_and_blobs::(ForkName::Deneb, NumBlobs::Random, &kzg, &mut rng); + generate_rand_block_and_blobs::(ForkName::Deneb, NumBlobs::Random, &mut rng); let mut blobs: FixedVector<_, ::MaxBlobsPerBlock> = FixedVector::default(); for blob in blobs_vec { diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index a4abb9010..a77da4c8e 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -2526,7 +2526,6 @@ pub enum NumBlobs { pub fn generate_rand_block_and_blobs( fork_name: ForkName, num_blobs: NumBlobs, - kzg: &Kzg, rng: &mut impl Rng, ) -> (SignedBeaconBlock>, Vec>) { let inner = map_fork_name!(fork_name, BeaconBlock, <_>::random_for_test(rng)); @@ -2540,8 +2539,7 @@ pub fn generate_rand_block_and_blobs( NumBlobs::None => 0, }; let (bundle, transactions) = - execution_layer::test_utils::generate_random_blobs::(num_blobs, kzg, rng) - .unwrap(); + execution_layer::test_utils::generate_blobs::(num_blobs).unwrap(); payload.execution_payload.transactions = <_>::default(); for tx in Vec::from(transactions) { diff --git a/beacon_node/execution_layer/Cargo.toml b/beacon_node/execution_layer/Cargo.toml index 46c585bb0..7f6526898 100644 --- a/beacon_node/execution_layer/Cargo.toml +++ b/beacon_node/execution_layer/Cargo.toml @@ -50,3 +50,4 @@ triehash = "0.8.4" hash-db = "0.15.2" pretty_reqwest_error = { workspace = true } arc-swap = "1.6.0" +eth2_network_config = { workspace = true } 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 6b638bb7f..b91c9b51a 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 @@ -10,7 +10,7 @@ use crate::{ ExecutionBlockWithTransactions, }; use eth2::types::BlobsBundle; -use kzg::Kzg; +use kzg::{Kzg, KzgCommitment, KzgProof}; use parking_lot::Mutex; use rand::{rngs::StdRng, Rng, SeedableRng}; use serde::{Deserialize, Serialize}; @@ -20,12 +20,16 @@ use std::sync::Arc; use tree_hash::TreeHash; use tree_hash_derive::TreeHash; use types::{ - BlobSidecar, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, - ExecutionPayloadDeneb, ExecutionPayloadHeader, ExecutionPayloadMerge, ForkName, Hash256, - Transaction, Transactions, Uint256, + Blob, ChainSpec, EthSpec, EthSpecId, ExecutionBlockHash, ExecutionPayload, + ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadHeader, ExecutionPayloadMerge, + ForkName, Hash256, Transaction, Transactions, Uint256, }; use super::DEFAULT_TERMINAL_BLOCK; +use ssz::Decode; + +const TEST_BLOB_BUNDLE_MAINNET: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz"); +const TEST_BLOB_BUNDLE_MINIMAL: &[u8] = include_bytes!("fixtures/minimal/test_blobs_bundle.ssz"); const GAS_LIMIT: u64 = 16384; const GAS_USED: u64 = GAS_LIMIT - 1; @@ -627,8 +631,7 @@ impl ExecutionBlockGenerator { // get random number between 0 and Max Blobs let mut rng = self.rng.lock(); let num_blobs = rng.gen::() % (T::max_blobs_per_block() + 1); - let kzg = self.kzg.as_ref().ok_or("kzg not initialized")?; - let (bundle, transactions) = generate_random_blobs(num_blobs, kzg, &mut *rng)?; + let (bundle, transactions) = generate_blobs(num_blobs)?; for tx in Vec::from(transactions) { execution_payload .transactions_mut() @@ -645,30 +648,51 @@ impl ExecutionBlockGenerator { } } -pub fn generate_random_blobs( +pub fn load_test_blobs_bundle() -> Result<(KzgCommitment, KzgProof, Blob), String> { + let blob_bundle_bytes = match E::spec_name() { + EthSpecId::Mainnet => TEST_BLOB_BUNDLE_MAINNET, + EthSpecId::Minimal => TEST_BLOB_BUNDLE_MINIMAL, + EthSpecId::Gnosis => { + return Err("Test blobs bundle not available for Gnosis preset".to_string()) + } + }; + + let BlobsBundle { + commitments, + proofs, + blobs, + } = BlobsBundle::::from_ssz_bytes(blob_bundle_bytes) + .map_err(|e| format!("Unable to decode SSZ: {:?}", e))?; + + Ok(( + commitments + .get(0) + .cloned() + .ok_or("commitment missing in test bundle")?, + proofs + .get(0) + .cloned() + .ok_or("proof missing in test bundle")?, + blobs.get(0).cloned().ok_or("blob missing in test bundle")?, + )) +} + +pub fn generate_blobs( n_blobs: usize, - kzg: &Kzg, - rng: &mut R, -) -> Result<(BlobsBundle, Transactions), String> { - let mut bundle = BlobsBundle::::default(); +) -> Result<(BlobsBundle, Transactions), String> { + let (kzg_commitment, kzg_proof, blob) = load_test_blobs_bundle::()?; + + let mut bundle = BlobsBundle::::default(); let mut transactions = vec![]; + for blob_index in 0..n_blobs { - let random_valid_sidecar = BlobSidecar::::random_valid(rng, kzg)?; - - let BlobSidecar { - blob, - kzg_commitment, - kzg_proof, - .. - } = random_valid_sidecar; - - let tx = static_valid_tx::() + let tx = static_valid_tx::() .map_err(|e| format!("error creating valid tx SSZ bytes: {:?}", e))?; transactions.push(tx); bundle .blobs - .push(blob) + .push(blob.clone()) .map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?; bundle .commitments @@ -797,7 +821,8 @@ pub fn generate_pow_block( #[cfg(test)] mod test { use super::*; - use types::MainnetEthSpec; + use kzg::TrustedSetup; + use types::{MainnetEthSpec, MinimalEthSpec}; #[test] fn pow_chain_only() { @@ -859,4 +884,33 @@ mod test { assert!(generator.block_by_number(next_i).is_none()); } } + + #[test] + fn valid_test_blobs() { + assert!( + validate_blob::().unwrap(), + "Mainnet preset test blobs bundle should contain valid proofs" + ); + assert!( + validate_blob::().unwrap(), + "Minimal preset test blobs bundle should contain valid proofs" + ); + } + + fn validate_blob() -> Result { + let kzg = load_kzg::()?; + let (kzg_commitment, kzg_proof, blob) = load_test_blobs_bundle::()?; + let kzg_blob = E::blob_from_bytes(blob.as_ref()) + .map_err(|e| format!("Error converting blob to kzg blob: {e:?}"))?; + kzg.verify_blob_kzg_proof(&kzg_blob, kzg_commitment, kzg_proof) + .map_err(|e| format!("Invalid blobs bundle: {e:?}")) + } + + fn load_kzg() -> Result, String> { + let trusted_setup: TrustedSetup = + serde_json::from_reader(eth2_network_config::get_trusted_setup::()) + .map_err(|e| format!("Unable to read trusted setup file: {e:?}"))?; + Kzg::new_from_trusted_setup(trusted_setup) + .map_err(|e| format!("Failed to load trusted setup: {e:?}")) + } } diff --git a/beacon_node/execution_layer/src/test_utils/fixtures/mainnet/test_blobs_bundle.ssz b/beacon_node/execution_layer/src/test_utils/fixtures/mainnet/test_blobs_bundle.ssz new file mode 100644 index 000000000..8ef325a00 Binary files /dev/null and b/beacon_node/execution_layer/src/test_utils/fixtures/mainnet/test_blobs_bundle.ssz differ diff --git a/beacon_node/execution_layer/src/test_utils/fixtures/minimal/test_blobs_bundle.ssz b/beacon_node/execution_layer/src/test_utils/fixtures/minimal/test_blobs_bundle.ssz new file mode 100644 index 000000000..366a467b2 Binary files /dev/null and b/beacon_node/execution_layer/src/test_utils/fixtures/minimal/test_blobs_bundle.ssz differ diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index f56a04b07..dc3f61815 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -25,8 +25,8 @@ use warp::{http::StatusCode, Filter, Rejection}; use crate::EngineCapabilities; pub use execution_block_generator::{ - generate_genesis_block, generate_genesis_header, generate_pow_block, generate_random_blobs, - Block, ExecutionBlockGenerator, + generate_blobs, generate_genesis_block, generate_genesis_header, generate_pow_block, Block, + ExecutionBlockGenerator, }; pub use hook::Hook; pub use mock_builder::{MockBuilder, Operation}; diff --git a/beacon_node/network/src/sync/block_lookups/tests.rs b/beacon_node/network/src/sync/block_lookups/tests.rs index 59ac9c433..bd1e72ee1 100644 --- a/beacon_node/network/src/sync/block_lookups/tests.rs +++ b/beacon_node/network/src/sync/block_lookups/tests.rs @@ -91,10 +91,8 @@ impl TestRig { fork_name: ForkName, num_blobs: NumBlobs, ) -> (SignedBeaconBlock, Vec>) { - let kzg = self.harness.chain.kzg.as_ref().unwrap(); let rng = &mut self.rng; - - generate_rand_block_and_blobs::(fork_name, num_blobs, kzg.as_ref(), rng) + generate_rand_block_and_blobs::(fork_name, num_blobs, rng) } #[track_caller] diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index 7f3040a9b..e87f254f1 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -7,7 +7,7 @@ use mediatype::{names, MediaType, MediaTypeList}; use serde::{Deserialize, Deserializer, Serialize}; use serde_json::Value; use ssz::{Decode, DecodeError}; -use ssz_derive::Encode; +use ssz_derive::{Decode, Encode}; use std::convert::TryFrom; use std::fmt::{self, Display}; use std::str::{from_utf8, FromStr}; @@ -2012,7 +2012,7 @@ pub struct ExecutionPayloadAndBlobs { pub blobs_bundle: BlobsBundle, } -#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Encode)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Encode, Decode)] #[serde(bound = "E: EthSpec")] pub struct BlobsBundle { pub commitments: KzgCommitments,