Make BeaconChain::kzg field mandatory (#6267)

* make kzg field required

* update todo

* always load trusted setup WIP

* fmt

* use new rust_eth_kzg version

* merge conlficts

* add kzg fn with trusted setup disabled

* as_slice

* add kzg with no precomp

* ignore udep for kzg

* refactor kzg init

* fix peerdas kzg schedule

* fix

* udeps

* uuuudeps

* merge conflict resolved

* merge conflict

* merge conflicts

* resolve TODO

* update

* move kzg to a test util fn

* remove trusted setup default impl

* lint fmt

* fix failing test

* lint

* fix test

* Merge branch 'unstable' into beacon-chain-kzg-field-required
This commit is contained in:
Eitan Seri-Levi
2024-09-22 21:54:32 -07:00
committed by GitHub
parent 18c97a7d64
commit b619f1ab5c
33 changed files with 190 additions and 212 deletions

8
Cargo.lock generated
View File

@@ -1408,6 +1408,7 @@ dependencies = [
"genesis",
"http_api",
"http_metrics",
"kzg",
"lighthouse_metrics",
"lighthouse_network",
"monitoring_api",
@@ -1415,6 +1416,7 @@ dependencies = [
"operation_pool",
"sensitive_url",
"serde",
"serde_json",
"serde_yaml",
"slasher",
"slasher_service",
@@ -2621,6 +2623,7 @@ dependencies = [
"discv5",
"eth2_config",
"ethereum_ssz",
"kzg",
"logging",
"pretty_reqwest_error",
"reqwest",
@@ -4413,7 +4416,6 @@ dependencies = [
"c-kzg",
"criterion",
"derivative",
"eth2_network_config",
"ethereum_hashing",
"ethereum_serde_utils",
"ethereum_ssz",
@@ -5641,6 +5643,7 @@ dependencies = [
"derivative",
"error-chain",
"eth2",
"eth2_network_config",
"ethereum_ssz",
"execution_layer",
"fnv",
@@ -5650,6 +5653,7 @@ dependencies = [
"hex",
"igd-next",
"itertools 0.10.5",
"kzg",
"lighthouse_metrics",
"lighthouse_network",
"logging",
@@ -5658,6 +5662,7 @@ dependencies = [
"operation_pool",
"parking_lot 0.12.3",
"rand",
"serde_json",
"slog",
"slog-async",
"slog-term",
@@ -7746,6 +7751,7 @@ dependencies = [
"eth2_network_config",
"execution_layer",
"futures",
"kzg",
"node_test_rig",
"parking_lot 0.12.3",
"rayon",

View File

@@ -1,11 +1,11 @@
use std::sync::Arc;
use beacon_chain::kzg_utils::{blobs_to_data_column_sidecars, reconstruct_data_columns};
use beacon_chain::test_utils::get_kzg;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use bls::Signature;
use eth2_network_config::TRUSTED_SETUP_BYTES;
use kzg::{Kzg, KzgCommitment, TrustedSetup};
use kzg::KzgCommitment;
use types::{
beacon_block_body::KzgCommitments, BeaconBlock, BeaconBlockDeneb, Blob, BlobsList, ChainSpec,
EmptyBlock, EthSpec, MainnetEthSpec, SignedBeaconBlock,
@@ -35,11 +35,7 @@ fn all_benches(c: &mut Criterion) {
type E = MainnetEthSpec;
let spec = Arc::new(E::default_spec());
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES)
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
.expect("should have trusted setup");
let kzg = Arc::new(Kzg::new_from_trusted_setup(trusted_setup).expect("should create kzg"));
let kzg = get_kzg(&spec);
for blob_count in [1, 2, 3, 6] {
let kzg = kzg.clone();
let (signed_block, blob_sidecars) = create_test_block_and_blobs::<E>(blob_count, &spec);

View File

@@ -497,7 +497,7 @@ pub struct BeaconChain<T: BeaconChainTypes> {
/// they are collected and combined.
pub data_availability_checker: Arc<DataAvailabilityChecker<T>>,
/// The KZG trusted setup used by this chain.
pub kzg: Option<Arc<Kzg>>,
pub kzg: Arc<Kzg>,
}
pub enum BeaconBlockResponseWrapper<E: EthSpec> {
@@ -5682,10 +5682,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let kzg_proofs = Vec::from(proofs);
let kzg = self
.kzg
.as_ref()
.ok_or(BlockProductionError::TrustedSetupNotInitialized)?;
let kzg = self.kzg.as_ref();
kzg_utils::validate_blobs::<T::EthSpec>(
kzg,
expected_kzg_commitments,

View File

@@ -115,13 +115,6 @@ pub enum GossipBlobError {
index: u64,
},
/// `Kzg` struct hasn't been initialized. This is an internal error.
///
/// ## Peer scoring
///
/// The peer isn't faulty, This is an internal error.
KzgNotInitialized,
/// The kzg verification failed.
///
/// ## Peer scoring
@@ -559,11 +552,9 @@ pub fn validate_blob_sidecar_for_gossip<T: BeaconChainTypes>(
}
// Kzg verification for gossip blob sidecar
let kzg = chain
.kzg
.as_ref()
.ok_or(GossipBlobError::KzgNotInitialized)?;
let kzg_verified_blob = KzgVerifiedBlob::new(blob_sidecar, kzg, seen_timestamp)
let kzg = chain.kzg.as_ref();
let kzg_verified_blob = KzgVerifiedBlob::new(blob_sidecar.clone(), kzg, seen_timestamp)
.map_err(GossipBlobError::KzgError)?;
let blob_sidecar = &kzg_verified_blob.blob;

View File

@@ -789,19 +789,11 @@ fn build_gossip_verified_data_columns<T: BeaconChainTypes>(
// Only attempt to build data columns if blobs is non empty to avoid skewing the metrics.
.filter(|b| !b.is_empty())
.map(|blobs| {
// NOTE: we expect KZG to be initialized if the blobs are present
let kzg = chain
.kzg
.as_ref()
.ok_or(BlockContentsError::DataColumnError(
GossipDataColumnError::KzgNotInitialized,
))?;
let mut timer = metrics::start_timer_vec(
&metrics::DATA_COLUMN_SIDECAR_COMPUTATION,
&[&blobs.len().to_string()],
);
let sidecars = blobs_to_data_column_sidecars(&blobs, block, kzg, &chain.spec)
let sidecars = blobs_to_data_column_sidecars(&blobs, block, &chain.kzg, &chain.spec)
.discard_timer_on_break(&mut timer)?;
drop(timer);
let mut gossip_verified_data_columns = vec![];

View File

@@ -101,7 +101,7 @@ pub struct BeaconChainBuilder<T: BeaconChainTypes> {
// Pending I/O batch that is constructed during building and should be executed atomically
// alongside `PersistedBeaconChain` storage when `BeaconChainBuilder::build` is called.
pending_io_batch: Vec<KeyValueStoreOp>,
kzg: Option<Arc<Kzg>>,
kzg: Arc<Kzg>,
task_executor: Option<TaskExecutor>,
validator_monitor_config: Option<ValidatorMonitorConfig>,
import_all_data_columns: bool,
@@ -120,7 +120,7 @@ where
///
/// The `_eth_spec_instance` parameter is only supplied to make concrete the `E` trait.
/// This should generally be either the `MinimalEthSpec` or `MainnetEthSpec` types.
pub fn new(_eth_spec_instance: E) -> Self {
pub fn new(_eth_spec_instance: E, kzg: Arc<Kzg>) -> Self {
Self {
store: None,
store_migrator_config: None,
@@ -143,7 +143,7 @@ where
beacon_graffiti: GraffitiOrigin::default(),
slasher: None,
pending_io_batch: vec![],
kzg: None,
kzg,
task_executor: None,
validator_monitor_config: None,
import_all_data_columns: false,
@@ -694,11 +694,6 @@ where
self
}
pub fn kzg(mut self, kzg: Option<Arc<Kzg>>) -> Self {
self.kzg = kzg;
self
}
/// Consumes `self`, returning a `BeaconChain` if all required parameters have been supplied.
///
/// An error will be returned at runtime if all required parameters have not been configured.
@@ -1157,7 +1152,7 @@ fn descriptive_db_error(item: &str, error: &StoreError) -> String {
#[cfg(test)]
mod test {
use super::*;
use crate::test_utils::EphemeralHarnessType;
use crate::test_utils::{get_kzg, EphemeralHarnessType};
use ethereum_hashing::hash;
use genesis::{
generate_deterministic_keypairs, interop_genesis_state, DEFAULT_ETH1_BLOCK_HASH,
@@ -1204,7 +1199,9 @@ mod test {
let (shutdown_tx, _) = futures::channel::mpsc::channel(1);
let runtime = TestRuntime::default();
let chain = Builder::new(MinimalEthSpec)
let kzg = get_kzg(&spec);
let chain = Builder::new(MinimalEthSpec, kzg)
.logger(log.clone())
.store(Arc::new(store))
.task_executor(runtime.task_executor.clone())

View File

@@ -69,7 +69,7 @@ pub const STATE_LRU_CAPACITY: usize = STATE_LRU_CAPACITY_NON_ZERO.get();
pub struct DataAvailabilityChecker<T: BeaconChainTypes> {
availability_cache: Arc<DataAvailabilityCheckerInner<T>>,
slot_clock: T::SlotClock,
kzg: Option<Arc<Kzg>>,
kzg: Arc<Kzg>,
spec: Arc<ChainSpec>,
}
@@ -97,7 +97,7 @@ impl<E: EthSpec> Debug for Availability<E> {
impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
pub fn new(
slot_clock: T::SlotClock,
kzg: Option<Arc<Kzg>>,
kzg: Arc<Kzg>,
store: BeaconStore<T>,
import_all_data_columns: bool,
spec: ChainSpec,
@@ -190,17 +190,16 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
epoch: Epoch,
blobs: FixedBlobSidecarList<T::EthSpec>,
) -> Result<Availability<T::EthSpec>, AvailabilityCheckError> {
let Some(kzg) = self.kzg.as_ref() else {
return Err(AvailabilityCheckError::KzgNotInitialized);
};
let seen_timestamp = self
.slot_clock
.now_duration()
.ok_or(AvailabilityCheckError::SlotClockError)?;
let verified_blobs =
KzgVerifiedBlobList::new(Vec::from(blobs).into_iter().flatten(), kzg, seen_timestamp)
let verified_blobs = KzgVerifiedBlobList::new(
Vec::from(blobs).into_iter().flatten(),
&self.kzg,
seen_timestamp,
)
.map_err(AvailabilityCheckError::Kzg)?;
self.availability_cache
@@ -217,23 +216,20 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
custody_columns: DataColumnSidecarList<T::EthSpec>,
) -> Result<(Availability<T::EthSpec>, DataColumnsToPublish<T::EthSpec>), AvailabilityCheckError>
{
let Some(kzg) = self.kzg.as_ref() else {
return Err(AvailabilityCheckError::KzgNotInitialized);
};
// TODO(das): report which column is invalid for proper peer scoring
// TODO(das): batch KZG verification here
let verified_custody_columns = custody_columns
.into_iter()
.map(|column| {
Ok(KzgVerifiedCustodyDataColumn::from_asserted_custody(
KzgVerifiedDataColumn::new(column, kzg).map_err(AvailabilityCheckError::Kzg)?,
KzgVerifiedDataColumn::new(column, &self.kzg)
.map_err(AvailabilityCheckError::Kzg)?,
))
})
.collect::<Result<Vec<_>, AvailabilityCheckError>>()?;
self.availability_cache.put_kzg_verified_data_columns(
kzg,
&self.kzg,
block_root,
epoch,
verified_custody_columns,
@@ -269,9 +265,6 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
gossip_data_columns: Vec<GossipVerifiedDataColumn<T>>,
) -> Result<(Availability<T::EthSpec>, DataColumnsToPublish<T::EthSpec>), AvailabilityCheckError>
{
let Some(kzg) = self.kzg.as_ref() else {
return Err(AvailabilityCheckError::KzgNotInitialized);
};
let epoch = slot.epoch(T::EthSpec::slots_per_epoch());
let custody_columns = gossip_data_columns
@@ -280,7 +273,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
.collect::<Vec<_>>();
self.availability_cache.put_kzg_verified_data_columns(
kzg,
&self.kzg,
block_root,
epoch,
custody_columns,
@@ -314,11 +307,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
let (block_root, block, blobs, data_columns) = block.deconstruct();
if self.blobs_required_for_block(&block) {
return if let Some(blob_list) = blobs.as_ref() {
let kzg = self
.kzg
.as_ref()
.ok_or(AvailabilityCheckError::KzgNotInitialized)?;
verify_kzg_for_blob_list(blob_list.iter(), kzg)
verify_kzg_for_blob_list(blob_list.iter(), &self.kzg)
.map_err(AvailabilityCheckError::Kzg)?;
Ok(MaybeAvailableBlock::Available(AvailableBlock {
block_root,
@@ -334,15 +323,11 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
}
if self.data_columns_required_for_block(&block) {
return if let Some(data_column_list) = data_columns.as_ref() {
let kzg = self
.kzg
.as_ref()
.ok_or(AvailabilityCheckError::KzgNotInitialized)?;
verify_kzg_for_data_column_list(
data_column_list
.iter()
.map(|custody_column| custody_column.as_data_column()),
kzg,
&self.kzg,
)
.map_err(AvailabilityCheckError::Kzg)?;
Ok(MaybeAvailableBlock::Available(AvailableBlock {
@@ -395,11 +380,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
// verify kzg for all blobs at once
if !all_blobs.is_empty() {
let kzg = self
.kzg
.as_ref()
.ok_or(AvailabilityCheckError::KzgNotInitialized)?;
verify_kzg_for_blob_list(all_blobs.iter(), kzg)?;
verify_kzg_for_blob_list(all_blobs.iter(), &self.kzg)?;
}
let all_data_columns = blocks
@@ -415,11 +396,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
// verify kzg for all data columns at once
if !all_data_columns.is_empty() {
let kzg = self
.kzg
.as_ref()
.ok_or(AvailabilityCheckError::KzgNotInitialized)?;
verify_kzg_for_data_column_list(all_data_columns.iter(), kzg)?;
verify_kzg_for_data_column_list(all_data_columns.iter(), &self.kzg)?;
}
for block in blocks {

View File

@@ -4,7 +4,6 @@ use types::{BeaconStateError, Hash256};
#[derive(Debug)]
pub enum Error {
Kzg(KzgError),
KzgNotInitialized,
KzgVerificationFailed,
KzgCommitmentMismatch {
blob_commitment: KzgCommitment,
@@ -36,8 +35,7 @@ pub enum ErrorCategory {
impl Error {
pub fn category(&self) -> ErrorCategory {
match self {
Error::KzgNotInitialized
| Error::SszTypes(_)
Error::SszTypes(_)
| Error::MissingBlobs
| Error::MissingCustodyColumns
| Error::StoreError(_)

View File

@@ -52,12 +52,6 @@ pub enum GossipDataColumnError {
data_column_slot: Slot,
parent_slot: Slot,
},
/// `Kzg` struct hasn't been initialized. This is an internal error.
///
/// ## Peer scoring
///
/// The peer isn't faulty, This is an internal error.
KzgNotInitialized,
/// The kzg verification failed.
///
/// ## Peer scoring
@@ -382,12 +376,8 @@ pub fn validate_data_column_sidecar_for_gossip<T: BeaconChainTypes>(
let parent_block = verify_parent_block_and_finalized_descendant(data_column.clone(), chain)?;
verify_slot_higher_than_parent(&parent_block, column_slot)?;
verify_proposer_and_signature(&data_column, &parent_block, chain)?;
let kzg = chain
.kzg
.clone()
.ok_or(GossipDataColumnError::KzgNotInitialized)?;
let kzg_verified_data_column = verify_kzg_for_data_column(data_column.clone(), &kzg)
let kzg = &chain.kzg;
let kzg_verified_data_column = verify_kzg_for_data_column(data_column.clone(), kzg)
.map_err(GossipDataColumnError::InvalidKzgProof)?;
chain

View File

@@ -291,7 +291,6 @@ pub enum BlockProductionError {
TokioJoin(JoinError),
BeaconChain(BeaconChainError),
InvalidPayloadFork,
TrustedSetupNotInitialized,
InvalidBlockVariant(String),
KzgError(kzg::Error),
FailedToBuildBlobSidecars(String),

View File

@@ -290,8 +290,7 @@ pub fn reconstruct_data_columns<E: EthSpec>(
mod test {
use crate::kzg_utils::{blobs_to_data_column_sidecars, reconstruct_data_columns};
use bls::Signature;
use eth2_network_config::TRUSTED_SETUP_BYTES;
use kzg::{Kzg, KzgCommitment, TrustedSetup};
use kzg::{trusted_setup::get_trusted_setup, Kzg, KzgCommitment, TrustedSetup};
use types::{
beacon_block_body::KzgCommitments, BeaconBlock, BeaconBlockDeneb, Blob, BlobsList,
ChainSpec, EmptyBlock, EthSpec, MainnetEthSpec, SignedBeaconBlock,
@@ -377,7 +376,7 @@ mod test {
}
fn get_kzg() -> Kzg {
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES)
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
.expect("should have trusted setup");
Kzg::new_from_trusted_setup_das_enabled(trusted_setup).expect("should create kzg")

View File

@@ -18,7 +18,6 @@ use crate::{
};
use bls::get_withdrawal_credentials;
use eth2::types::SignedBlockContentsTuple;
use eth2_network_config::TRUSTED_SETUP_BYTES;
use execution_layer::test_utils::generate_genesis_header;
use execution_layer::{
auth::JwtKey,
@@ -31,6 +30,7 @@ use execution_layer::{
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::trusted_setup::get_trusted_setup;
use kzg::{Kzg, TrustedSetup};
use merkle_proof::MerkleTree;
use operation_pool::ReceivedPreCapella;
@@ -75,22 +75,40 @@ pub const FORK_NAME_ENV_VAR: &str = "FORK_NAME";
// a different value.
pub const DEFAULT_TARGET_AGGREGATORS: u64 = u64::MAX;
pub static KZG: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES)
static KZG: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
.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");
Arc::new(kzg)
});
pub static KZG_PEERDAS: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES)
static KZG_PEERDAS: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
.expect("should have trusted setup");
let kzg = Kzg::new_from_trusted_setup_das_enabled(trusted_setup).expect("should create kzg");
Arc::new(kzg)
});
static KZG_NO_PRECOMP: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
.expect("should have trusted setup");
let kzg = Kzg::new_from_trusted_setup_no_precomp(trusted_setup).expect("should create kzg");
Arc::new(kzg)
});
pub fn get_kzg(spec: &ChainSpec) -> Arc<Kzg> {
if spec.eip7594_fork_epoch.is_some() {
KZG_PEERDAS.clone()
} else if spec.deneb_fork_epoch.is_some() {
KZG.clone()
} else {
KZG_NO_PRECOMP.clone()
}
}
pub type BaseHarnessType<E, THotStore, TColdStore> =
Witness<TestingSlotClock, CachingEth1Backend<E>, E, THotStore, TColdStore>;
@@ -522,12 +540,13 @@ where
let validator_keypairs = self
.validator_keypairs
.expect("cannot build without validator keypairs");
let kzg = spec.deneb_fork_epoch.map(|_| KZG.clone());
let kzg = get_kzg(&spec);
let validator_monitor_config = self.validator_monitor_config.unwrap_or_default();
let chain_config = self.chain_config.unwrap_or_default();
let mut builder = BeaconChainBuilder::new(self.eth_spec_instance)
let mut builder = BeaconChainBuilder::new(self.eth_spec_instance, kzg.clone())
.logger(log.clone())
.custom_spec(spec.clone())
.store(self.store.expect("cannot build without store"))
@@ -546,8 +565,7 @@ where
log.clone(),
5,
)))
.validator_monitor_config(validator_monitor_config)
.kzg(kzg);
.validator_monitor_config(validator_monitor_config);
builder = if let Some(mutator) = self.initial_mutator {
mutator(builder)
@@ -602,7 +620,7 @@ pub fn mock_execution_layer_from_parts<E: EthSpec>(
HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64()
});
let kzg_opt = spec.deneb_fork_epoch.map(|_| KZG.clone());
let kzg = get_kzg(spec);
MockExecutionLayer::new(
task_executor,
@@ -612,7 +630,7 @@ pub fn mock_execution_layer_from_parts<E: EthSpec>(
prague_time,
Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()),
spec.clone(),
kzg_opt,
Some(kzg),
)
}
@@ -2842,9 +2860,10 @@ pub fn generate_rand_block_and_data_columns<E: EthSpec>(
SignedBeaconBlock<E, FullPayload<E>>,
Vec<Arc<DataColumnSidecar<E>>>,
) {
let kzg = get_kzg(spec);
let (block, blobs) = generate_rand_block_and_blobs(fork_name, num_blobs, rng);
let blob: BlobsList<E> = blobs.into_iter().map(|b| b.blob).collect::<Vec<_>>().into();
let data_columns = blobs_to_data_column_sidecars(&blob, &block, &KZG_PEERDAS, spec).unwrap();
let data_columns = blobs_to_data_column_sidecars(&blob, &block, &kzg, spec).unwrap();
(block, data_columns)
}

View File

@@ -25,7 +25,7 @@ async fn blob_sidecar_event_on_process_gossip_blob() {
let mut blob_event_receiver = event_handler.subscribe_blob_sidecar();
// build and process a gossip verified blob
let kzg = harness.chain.kzg.as_ref().unwrap();
let kzg = harness.chain.kzg.as_ref();
let mut rng = StdRng::seed_from_u64(0xDEADBEEF0BAD5EEDu64);
let sidecar = BlobSidecar::random_valid(&mut rng, kzg)
.map(Arc::new)
@@ -59,7 +59,7 @@ async fn blob_sidecar_event_on_process_rpc_blobs() {
let mut blob_event_receiver = event_handler.subscribe_blob_sidecar();
// build and process multiple rpc blobs
let kzg = harness.chain.kzg.as_ref().unwrap();
let kzg = harness.chain.kzg.as_ref();
let mut rng = StdRng::seed_from_u64(0xDEADBEEF0BAD5EEDu64);
let mut blob_1 = BlobSidecar::random_valid(&mut rng, kzg).unwrap();

View File

@@ -7,8 +7,8 @@ use beacon_chain::data_availability_checker::AvailableBlock;
use beacon_chain::schema_change::migrate_schema;
use beacon_chain::test_utils::SyncCommitteeStrategy;
use beacon_chain::test_utils::{
mock_execution_layer_from_parts, test_spec, AttestationStrategy, BeaconChainHarness,
BlockStrategy, DiskHarnessType, KZG,
get_kzg, mock_execution_layer_from_parts, test_spec, AttestationStrategy, BeaconChainHarness,
BlockStrategy, DiskHarnessType,
};
use beacon_chain::{
data_availability_checker::MaybeAvailableBlock, historical_blocks::HistoricalBlockError,
@@ -164,7 +164,7 @@ async fn light_client_bootstrap_test() {
.unwrap()
.unwrap();
let kzg = spec.deneb_fork_epoch.map(|_| KZG.clone());
let kzg = get_kzg(&spec);
let mock =
mock_execution_layer_from_parts(&harness.spec, harness.runtime.task_executor.clone());
@@ -180,7 +180,7 @@ async fn light_client_bootstrap_test() {
let (shutdown_tx, _shutdown_rx) = futures::channel::mpsc::channel(1);
let beacon_chain = BeaconChainBuilder::<DiskHarnessType<E>>::new(MinimalEthSpec)
let beacon_chain = BeaconChainBuilder::<DiskHarnessType<E>>::new(MinimalEthSpec, kzg)
.store(store.clone())
.custom_spec(test_spec::<E>())
.task_executor(harness.chain.task_executor.clone())
@@ -203,7 +203,6 @@ async fn light_client_bootstrap_test() {
1,
)))
.execution_layer(Some(mock.el))
.kzg(kzg)
.build()
.expect("should build");
@@ -299,7 +298,7 @@ async fn light_client_updates_test() {
.unwrap()
.unwrap();
let kzg = spec.deneb_fork_epoch.map(|_| KZG.clone());
let kzg = get_kzg(&spec);
let mock =
mock_execution_layer_from_parts(&harness.spec, harness.runtime.task_executor.clone());
@@ -324,7 +323,7 @@ async fn light_client_updates_test() {
let (shutdown_tx, _shutdown_rx) = futures::channel::mpsc::channel(1);
let beacon_chain = BeaconChainBuilder::<DiskHarnessType<E>>::new(MinimalEthSpec)
let beacon_chain = BeaconChainBuilder::<DiskHarnessType<E>>::new(MinimalEthSpec, kzg)
.store(store.clone())
.custom_spec(test_spec::<E>())
.task_executor(harness.chain.task_executor.clone())
@@ -347,7 +346,6 @@ async fn light_client_updates_test() {
1,
)))
.execution_layer(Some(mock.el))
.kzg(kzg)
.build()
.expect("should build");
@@ -2680,7 +2678,8 @@ async fn weak_subjectivity_sync_test(slots: Vec<Slot>, checkpoint_slot: Slot) {
let store = get_store(&temp2);
let spec = test_spec::<E>();
let seconds_per_slot = spec.seconds_per_slot;
let kzg = spec.deneb_fork_epoch.map(|_| KZG.clone());
let kzg = get_kzg(&spec);
let mock =
mock_execution_layer_from_parts(&harness.spec, harness.runtime.task_executor.clone());
@@ -2694,7 +2693,7 @@ async fn weak_subjectivity_sync_test(slots: Vec<Slot>, checkpoint_slot: Slot) {
);
slot_clock.set_slot(harness.get_current_slot().as_u64());
let beacon_chain = BeaconChainBuilder::<DiskHarnessType<E>>::new(MinimalEthSpec)
let beacon_chain = BeaconChainBuilder::<DiskHarnessType<E>>::new(MinimalEthSpec, kzg)
.store(store.clone())
.custom_spec(test_spec::<E>())
.task_executor(harness.chain.task_executor.clone())
@@ -2717,7 +2716,6 @@ async fn weak_subjectivity_sync_test(slots: Vec<Slot>, checkpoint_slot: Slot) {
1,
)))
.execution_layer(Some(mock.el))
.kzg(kzg)
.build()
.expect("should build");

View File

@@ -20,6 +20,7 @@ types = { workspace = true }
eth2_config = { workspace = true }
slot_clock = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
error-chain = { workspace = true }
slog = { workspace = true }
tokio = { workspace = true }
@@ -27,6 +28,7 @@ futures = { workspace = true }
dirs = { workspace = true }
eth1 = { workspace = true }
eth2 = { workspace = true }
kzg = { workspace = true }
sensitive_url = { workspace = true }
genesis = { workspace = true }
task_executor = { workspace = true }

View File

@@ -195,7 +195,17 @@ where
None
};
let builder = BeaconChainBuilder::new(eth_spec_instance)
let kzg_err_msg = |e| format!("Failed to load trusted setup: {:?}", e);
let trusted_setup = config.trusted_setup.clone();
let kzg = if spec.is_peer_das_scheduled() {
Kzg::new_from_trusted_setup_das_enabled(trusted_setup).map_err(kzg_err_msg)?
} else if spec.deneb_fork_epoch.is_some() {
Kzg::new_from_trusted_setup(trusted_setup).map_err(kzg_err_msg)?
} else {
Kzg::new_from_trusted_setup_no_precomp(trusted_setup).map_err(kzg_err_msg)?
};
let builder = BeaconChainBuilder::new(eth_spec_instance, Arc::new(kzg))
.logger(context.log().clone())
.store(store)
.task_executor(context.executor.clone())
@@ -623,20 +633,6 @@ where
ClientGenesis::FromStore => builder.resume_from_db().map(|v| (v, None))?,
};
let beacon_chain_builder = if let Some(trusted_setup) = config.trusted_setup {
let kzg_err_msg = |e| format!("Failed to load trusted setup: {:?}", e);
let kzg = if spec.is_peer_das_scheduled() {
Kzg::new_from_trusted_setup_das_enabled(trusted_setup).map_err(kzg_err_msg)?
} else {
Kzg::new_from_trusted_setup(trusted_setup).map_err(kzg_err_msg)?
};
beacon_chain_builder.kzg(Some(Arc::new(kzg)))
} else {
beacon_chain_builder
};
if config.sync_eth1_chain {
self.eth1_service = eth1_service_option;
}

View File

@@ -4,6 +4,7 @@ use beacon_chain::TrustedSetup;
use beacon_processor::BeaconProcessorConfig;
use directory::DEFAULT_ROOT_DIR;
use environment::LoggerConfig;
use kzg::trusted_setup::get_trusted_setup;
use network::NetworkConfig;
use sensitive_url::SensitiveUrl;
use serde::{Deserialize, Serialize};
@@ -75,7 +76,7 @@ pub struct Config {
pub chain: beacon_chain::ChainConfig,
pub eth1: eth1::Config,
pub execution_layer: Option<execution_layer::Config>,
pub trusted_setup: Option<TrustedSetup>,
pub trusted_setup: TrustedSetup,
pub http_api: http_api::Config,
pub http_metrics: http_metrics::Config,
pub monitoring_api: Option<monitoring_api::Config>,
@@ -89,6 +90,9 @@ pub struct Config {
impl Default for Config {
fn default() -> Self {
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
.expect("Unable to read trusted setup file");
Self {
data_dir: PathBuf::from(DEFAULT_ROOT_DIR),
db_name: "chain_db".to_string(),
@@ -103,7 +107,7 @@ impl Default for Config {
sync_eth1_chain: false,
eth1: <_>::default(),
execution_layer: None,
trusted_setup: None,
trusted_setup,
beacon_graffiti: GraffitiOrigin::default(),
http_api: <_>::default(),
http_metrics: <_>::default(),

View File

@@ -862,8 +862,7 @@ pub fn generate_pow_block(
#[cfg(test)]
mod test {
use super::*;
use eth2_network_config::TRUSTED_SETUP_BYTES;
use kzg::TrustedSetup;
use kzg::{trusted_setup::get_trusted_setup, TrustedSetup};
use types::{MainnetEthSpec, MinimalEthSpec};
#[test]
@@ -951,7 +950,8 @@ mod test {
}
fn load_kzg() -> Result<Kzg, String> {
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES)
let trusted_setup: TrustedSetup =
serde_json::from_reader(get_trusted_setup().as_slice())
.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:?}"))

View File

@@ -8,10 +8,13 @@ edition = { workspace = true }
sloggers = { workspace = true }
genesis = { workspace = true }
matches = "0.1.8"
serde_json = { workspace = true }
slog-term = { workspace = true }
slog-async = { workspace = true }
eth2 = { workspace = true }
gossipsub = { workspace = true }
eth2_network_config = { workspace = true }
kzg = { workspace = true }
[dependencies]
alloy-primitives = { workspace = true }

View File

@@ -696,8 +696,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
column_sidecar,
));
}
GossipDataColumnError::KzgNotInitialized
| GossipDataColumnError::PubkeyCacheTimeout
GossipDataColumnError::PubkeyCacheTimeout
| GossipDataColumnError::BeaconChainError(_) => {
crit!(
self.log,
@@ -839,9 +838,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
blob_sidecar,
));
}
GossipBlobError::KzgNotInitialized
| GossipBlobError::PubkeyCacheTimeout
| GossipBlobError::BeaconChainError(_) => {
GossipBlobError::PubkeyCacheTimeout | GossipBlobError::BeaconChainError(_) => {
crit!(
self.log,
"Internal error when verifying blob sidecar";

View File

@@ -385,8 +385,8 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
data_columns: Vec<Arc<DataColumnSidecar<T::EthSpec>>>,
_seen_timestamp: Duration,
) -> Result<(), String> {
let kzg = self.chain.kzg.as_ref().ok_or("Kzg not initialized")?;
verify_kzg_for_data_column_list(data_columns.iter(), kzg).map_err(|err| format!("{err:?}"))
verify_kzg_for_data_column_list(data_columns.iter(), &self.chain.kzg)
.map_err(|err| format!("{err:?}"))
}
/// Process a sampling completed event, inserting it into fork-choice
@@ -561,8 +561,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
})
.collect::<Vec<_>>(),
Err(e) => match e {
AvailabilityCheckError::StoreError(_)
| AvailabilityCheckError::KzgNotInitialized => {
AvailabilityCheckError::StoreError(_) => {
return (
0,
Err(ChainSegmentFailed {

View File

@@ -2,6 +2,7 @@ use super::*;
use beacon_chain::{
builder::{BeaconChainBuilder, Witness},
eth1_chain::CachingEth1Backend,
test_utils::get_kzg,
BeaconChain,
};
use futures::prelude::*;
@@ -45,12 +46,14 @@ impl TestBeaconChain {
let store =
HotColdDB::open_ephemeral(StoreConfig::default(), spec.clone(), log.clone()).unwrap();
let kzg = get_kzg(&spec);
let (shutdown_tx, _) = futures::channel::mpsc::channel(1);
let test_runtime = TestRuntime::default();
let chain = Arc::new(
BeaconChainBuilder::new(MainnetEthSpec)
BeaconChainBuilder::new(MainnetEthSpec, kzg.clone())
.logger(log.clone())
.custom_spec(spec.clone())
.store(Arc::new(store))

View File

@@ -396,13 +396,15 @@ pub fn get_config<E: EthSpec>(
}
// 4844 params
client_config.trusted_setup = context
if let Some(trusted_setup) = context
.eth2_network_config
.as_ref()
.and_then(|config| config.kzg_trusted_setup.as_ref())
.map(|trusted_setup_bytes| serde_json::from_slice(trusted_setup_bytes))
.map(|config| serde_json::from_slice(&config.kzg_trusted_setup))
.transpose()
.map_err(|e| format!("Unable to read trusted setup file: {}", e))?;
.map_err(|e| format!("Unable to read trusted setup file: {}", e))?
{
client_config.trusted_setup = trusted_setup;
};
// Override default trusted setup file if required
if let Some(trusted_setup_file_path) = cli_args.get_one::<String>("trusted-setup-file-override")
@@ -411,7 +413,7 @@ pub fn get_config<E: EthSpec>(
.map_err(|e| format!("Failed to open trusted setup file: {}", e))?;
let trusted_setup: TrustedSetup = serde_json::from_reader(file)
.map_err(|e| format!("Unable to read trusted setup file: {}", e))?;
client_config.trusted_setup = Some(trusted_setup);
client_config.trusted_setup = trusted_setup;
}
if let Some(freezer_dir) = cli_args.get_one::<String>("freezer-dir") {

View File

@@ -28,3 +28,4 @@ sensitive_url = { workspace = true }
slog = { workspace = true }
logging = { workspace = true }
bytes = { workspace = true }
kzg = { workspace = true }

View File

@@ -14,6 +14,7 @@
use bytes::Bytes;
use discv5::enr::{CombinedKey, Enr};
use eth2_config::{instantiate_hardcoded_nets, HardcodedNet};
use kzg::trusted_setup::get_trusted_setup;
use pretty_reqwest_error::PrettyReqwestError;
use reqwest::{Client, Error};
use sensitive_url::SensitiveUrl;
@@ -24,7 +25,7 @@ use std::io::{Read, Write};
use std::path::PathBuf;
use std::str::FromStr;
use std::time::Duration;
use types::{BeaconState, ChainSpec, Config, Epoch, EthSpec, EthSpecId, Hash256};
use types::{BeaconState, ChainSpec, Config, EthSpec, EthSpecId, Hash256};
use url::Url;
pub use eth2_config::GenesisStateSource;
@@ -43,26 +44,6 @@ instantiate_hardcoded_nets!(eth2_config);
pub const DEFAULT_HARDCODED_NETWORK: &str = "mainnet";
/// Contains the bytes from the trusted setup json.
/// The mainnet trusted setup is also reused in testnets.
///
/// This is done to ensure that testnets also inherit the high security and
/// randomness of the mainnet kzg trusted setup ceremony.
///
/// Note: The trusted setup for both mainnet and minimal presets are the same.
pub const TRUSTED_SETUP_BYTES: &[u8] =
include_bytes!("../built_in_network_configs/trusted_setup.json");
/// Returns `Some(TrustedSetup)` if the deneb fork epoch is set and `None` otherwise.
///
/// Returns an error if the trusted setup parsing failed.
fn get_trusted_setup_from_config(config: &Config) -> Option<Vec<u8>> {
config
.deneb_fork_epoch
.filter(|epoch| epoch.value != Epoch::max_value())
.map(|_| TRUSTED_SETUP_BYTES.to_vec())
}
/// A simple slice-or-vec enum to avoid cloning the beacon state bytes in the
/// binary whilst also supporting loading them from a file at runtime.
#[derive(Clone, PartialEq, Debug)]
@@ -104,7 +85,7 @@ pub struct Eth2NetworkConfig {
pub genesis_state_source: GenesisStateSource,
pub genesis_state_bytes: Option<GenesisStateBytes>,
pub config: Config,
pub kzg_trusted_setup: Option<Vec<u8>>,
pub kzg_trusted_setup: Vec<u8>,
}
impl Eth2NetworkConfig {
@@ -122,7 +103,7 @@ impl Eth2NetworkConfig {
fn from_hardcoded_net(net: &HardcodedNet) -> Result<Self, String> {
let config: Config = serde_yaml::from_reader(net.config)
.map_err(|e| format!("Unable to parse yaml config: {:?}", e))?;
let kzg_trusted_setup = get_trusted_setup_from_config(&config);
let kzg_trusted_setup = get_trusted_setup();
Ok(Self {
deposit_contract_deploy_block: serde_yaml::from_reader(net.deploy_block)
.map_err(|e| format!("Unable to parse deploy block: {:?}", e))?,
@@ -359,7 +340,7 @@ impl Eth2NetworkConfig {
(None, GenesisStateSource::Unknown)
};
let kzg_trusted_setup = get_trusted_setup_from_config(&config);
let kzg_trusted_setup = get_trusted_setup();
Ok(Self {
deposit_contract_deploy_block,
@@ -577,7 +558,7 @@ mod tests {
GenesisStateSource::Unknown
};
// With Deneb enabled by default we must set a trusted setup here.
let kzg_trusted_setup = get_trusted_setup_from_config(&config).unwrap();
let kzg_trusted_setup = get_trusted_setup();
let testnet = Eth2NetworkConfig {
deposit_contract_deploy_block,
@@ -588,7 +569,7 @@ mod tests {
.map(Encode::as_ssz_bytes)
.map(Into::into),
config,
kzg_trusted_setup: Some(kzg_trusted_setup),
kzg_trusted_setup,
};
testnet

View File

@@ -18,11 +18,11 @@ hex = { workspace = true }
ethereum_hashing = { workspace = true }
c-kzg = { workspace = true }
rust_eth_kzg = { workspace = true }
serde_json = { workspace = true }
[dev-dependencies]
criterion = { workspace = true }
serde_json = { workspace = true }
eth2_network_config = { workspace = true }
[[bench]]
name = "benchmark"

View File

@@ -1,11 +1,10 @@
use c_kzg::KzgSettings;
use criterion::{criterion_group, criterion_main, Criterion};
use eth2_network_config::TRUSTED_SETUP_BYTES;
use kzg::TrustedSetup;
use kzg::{trusted_setup::get_trusted_setup, TrustedSetup};
use rust_eth_kzg::{DASContext, TrustedSetup as PeerDASTrustedSetup};
pub fn bench_init_context(c: &mut Criterion) {
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES)
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
.expect("should have trusted setup");
@@ -22,7 +21,8 @@ pub fn bench_init_context(c: &mut Criterion) {
});
c.bench_function(&format!("Initialize context c-kzg (4844)"), |b| {
b.iter(|| {
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES)
let trusted_setup: TrustedSetup =
serde_json::from_reader(get_trusted_setup().as_slice())
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
.expect("should have trusted setup");
KzgSettings::load_trusted_setup(&trusted_setup.g1_points(), &trusted_setup.g2_points())

View File

@@ -1,6 +1,6 @@
mod kzg_commitment;
mod kzg_proof;
mod trusted_setup;
pub mod trusted_setup;
use rust_eth_kzg::{CellIndex, DASContext};
use std::fmt::Debug;
@@ -51,18 +51,41 @@ impl From<c_kzg::Error> for Error {
#[derive(Debug)]
pub struct Kzg {
trusted_setup: KzgSettings,
context: Option<DASContext>,
context: DASContext,
}
impl Kzg {
/// Load the kzg trusted setup parameters from a vec of G1 and G2 points.
pub fn new_from_trusted_setup(trusted_setup: TrustedSetup) -> Result<Self, Error> {
pub fn new_from_trusted_setup_no_precomp(trusted_setup: TrustedSetup) -> Result<Self, Error> {
let peerdas_trusted_setup = PeerDASTrustedSetup::from(&trusted_setup);
let context = DASContext::new(&peerdas_trusted_setup, rust_eth_kzg::UsePrecomp::No);
Ok(Self {
trusted_setup: KzgSettings::load_trusted_setup(
&trusted_setup.g1_points(),
&trusted_setup.g2_points(),
)?,
context: None,
context,
})
}
/// Load the kzg trusted setup parameters from a vec of G1 and G2 points.
pub fn new_from_trusted_setup(trusted_setup: TrustedSetup) -> Result<Self, Error> {
let peerdas_trusted_setup = PeerDASTrustedSetup::from(&trusted_setup);
let context = DASContext::new(
&peerdas_trusted_setup,
rust_eth_kzg::UsePrecomp::Yes {
width: rust_eth_kzg::constants::RECOMMENDED_PRECOMP_WIDTH,
},
);
Ok(Self {
trusted_setup: KzgSettings::load_trusted_setup(
&trusted_setup.g1_points(),
&trusted_setup.g2_points(),
)?,
context,
})
}
@@ -88,12 +111,12 @@ impl Kzg {
&trusted_setup.g1_points(),
&trusted_setup.g2_points(),
)?,
context: Some(context),
context,
})
}
fn context(&self) -> Result<&DASContext, Error> {
self.context.as_ref().ok_or(Error::DASContextUninitialized)
fn context(&self) -> &DASContext {
&self.context
}
/// Compute the kzg proof given a blob and its kzg commitment.
@@ -200,7 +223,7 @@ impl Kzg {
blob: KzgBlobRef<'_>,
) -> Result<CellsAndKzgProofs, Error> {
let (cells, proofs) = self
.context()?
.context()
.compute_cells_and_kzg_proofs(blob)
.map_err(Error::PeerDASKZG)?;
@@ -226,7 +249,7 @@ impl Kzg {
.iter()
.map(|commitment| commitment.as_ref())
.collect();
let verification_result = self.context()?.verify_cell_kzg_proof_batch(
let verification_result = self.context().verify_cell_kzg_proof_batch(
commitments.to_vec(),
columns,
cells.to_vec(),
@@ -247,7 +270,7 @@ impl Kzg {
cells: &[CellRef<'_>],
) -> Result<CellsAndKzgProofs, Error> {
let (cells, proofs) = self
.context()?
.context()
.recover_cells_and_kzg_proofs(cell_ids.to_vec(), cells.to_vec())
.map_err(Error::PeerDASKZG)?;

View File

@@ -5,6 +5,12 @@ use serde::{
Deserialize, Serialize,
};
pub const TRUSTED_SETUP_BYTES: &[u8] = include_bytes!("../trusted_setup.json");
pub fn get_trusted_setup() -> Vec<u8> {
TRUSTED_SETUP_BYTES.into()
}
/// Wrapper over a BLS G1 point's byte representation.
#[derive(Debug, Clone, PartialEq)]
struct G1Point([u8; BYTES_PER_G1_POINT]);

View File

@@ -1,7 +1,7 @@
use super::*;
use crate::case_result::compare_result;
use beacon_chain::kzg_utils::validate_blob;
use eth2_network_config::TRUSTED_SETUP_BYTES;
use kzg::trusted_setup::get_trusted_setup;
use kzg::{Cell, Error as KzgError, Kzg, KzgCommitment, KzgProof, TrustedSetup};
use serde::Deserialize;
use std::marker::PhantomData;
@@ -10,7 +10,7 @@ use std::sync::LazyLock;
use types::Blob;
static KZG: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES)
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
.map_err(|e| Error::InternalError(format!("Failed to initialize trusted setup: {:?}", e)))
.expect("failed to initialize trusted setup");
let kzg = Kzg::new_from_trusted_setup_das_enabled(trusted_setup)

View File

@@ -19,3 +19,4 @@ rayon = { workspace = true }
sensitive_url = { path = "../../common/sensitive_url" }
eth2_network_config = { workspace = true }
serde_json = { workspace = true }
kzg = { workspace = true }

View File

@@ -1,5 +1,5 @@
use crate::checks::epoch_delay;
use eth2_network_config::TRUSTED_SETUP_BYTES;
use kzg::trusted_setup::get_trusted_setup;
use node_test_rig::{
environment::RuntimeContext,
eth2::{types::StateId, BeaconNodeHttpClient},
@@ -46,8 +46,8 @@ fn default_client_config(network_params: LocalNetworkParams, genesis_time: u64)
beacon_config.chain.enable_light_client_server = true;
beacon_config.http_api.enable_light_client_server = true;
beacon_config.chain.optimistic_finalized_sync = false;
beacon_config.trusted_setup =
serde_json::from_reader(TRUSTED_SETUP_BYTES).expect("Trusted setup bytes should be valid");
beacon_config.trusted_setup = serde_json::from_reader(get_trusted_setup().as_slice())
.expect("Trusted setup bytes should be valid");
let el_config = execution_layer::Config {
execution_endpoint: Some(