From 9df968c99212962248ac85f9da06de1f2a2ce6cb Mon Sep 17 00:00:00 2001 From: Pawan Dhananjay Date: Thu, 16 Mar 2023 20:55:21 +0530 Subject: [PATCH] more progress --- beacon_node/beacon_chain/src/beacon_chain.rs | 38 ++-- .../beacon_chain/src/blob_verification.rs | 165 +++++++++--------- .../beacon_chain/src/block_verification.rs | 92 ++++++---- consensus/types/src/signed_blob.rs | 21 ++- 4 files changed, 181 insertions(+), 135 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 6d21187b09..482de67043 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -2682,6 +2682,7 @@ impl BeaconChain { metrics::inc_counter(&metrics::BLOCK_PROCESSING_REQUESTS); let slot = unverified_block.block().slot(); + let chain = self.clone(); let execution_pending = unverified_block.into_execution_pending_block( block_root, @@ -2694,8 +2695,6 @@ impl BeaconChain { .into_executed_block(execution_pending, count_unrealized) .await?; - let chain = self.clone(); - // Check if the executed block has all it's blobs available to qualify as a fully // available block let import_block = if let Ok(blobs) = self @@ -2840,12 +2839,12 @@ impl BeaconChain { payload_verification_outcome, parent_eth1_finalization_data, consensus_context, - } = execution_pending_block; + } = executed_block; let chain = self.clone(); let available_block = AvailableBlock { - block: block, + block: block.block_cloned(), blobs: blobs, }; @@ -2857,7 +2856,7 @@ impl BeaconChain { block_root, state, confirmed_state_roots, - payload_verification_status, + payload_verification_outcome.payload_verification_status, count_unrealized, parent_block, parent_eth1_finalization_data, @@ -2871,7 +2870,7 @@ impl BeaconChain { Ok(block_hash) } - /// Accepts a fully-verified block and imports it into the chain without performing any + /// Accepts a fully-verified and available block and imports it into the chain without performing any /// additional verification. /// /// An error is returned if the block was unable to be imported. It may be partially imported @@ -2896,7 +2895,7 @@ impl BeaconChain { // ----------------------------------------------------------------------------------------- let current_slot = self.slot()?; let current_epoch = current_slot.epoch(T::EthSpec::slots_per_epoch()); - let block = signed_block.message(); + let block = signed_block.block.message(); let post_exec_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_POST_EXEC_PROCESSING); // Check against weak subjectivity checkpoint. @@ -2933,9 +2932,14 @@ impl BeaconChain { let mut fork_choice = self.canonical_head.fork_choice_write_lock(); // Do not import a block that doesn't descend from the finalized root. - let signed_block = - check_block_is_finalized_checkpoint_or_descendant(self, &fork_choice, signed_block)?; - let block = signed_block.message(); + let signed_block = check_block_is_finalized_checkpoint_or_descendant( + self, + &fork_choice, + BlockWrapper::from(signed_block), + )?; + // TODO(pawan): fix this atrocity + let signed_block = signed_block.into_available_block().unwrap(); + let block = signed_block.block.message(); // Register the new block with the fork choice service. { @@ -3065,14 +3069,12 @@ impl BeaconChain { // margin, or younger (of higher epoch number). if block_epoch >= import_boundary { if let Some(blobs) = blobs { - if !blobs.blobs.is_empty() { - //FIXME(sean) using this for debugging for now - info!( - self.log, "Writing blobs to store"; - "block_root" => ?block_root - ); - ops.push(StoreOp::PutBlobs(block_root, blobs)); - } + //FIXME(sean) using this for debugging for now + info!( + self.log, "Writing blobs to store"; + "block_root" => ?block_root + ); + ops.push(StoreOp::PutBlobs(block_root, blobs)); } } } diff --git a/beacon_node/beacon_chain/src/blob_verification.rs b/beacon_node/beacon_chain/src/blob_verification.rs index ee51d47a21..35fb4c1429 100644 --- a/beacon_node/beacon_chain/src/blob_verification.rs +++ b/beacon_node/beacon_chain/src/blob_verification.rs @@ -1,8 +1,5 @@ -use derivative::Derivative; use slot_clock::SlotClock; -use ssz_types::VariableList; use std::sync::Arc; -use tokio::task::JoinHandle; use crate::beacon_chain::{ BeaconChain, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY, @@ -10,12 +7,10 @@ use crate::beacon_chain::{ }; use crate::BeaconChainError; use state_processing::per_block_processing::eip4844::eip4844::verify_kzg_commitments_against_transactions; -use types::blob_sidecar::BlobSidecar; use types::{ - BeaconBlockRef, BeaconStateError, EthSpec, Hash256, KzgCommitment, SignedBeaconBlock, - SignedBeaconBlockHeader, SignedBlobSidecar, Slot, Transactions, + BeaconBlockRef, BeaconStateError, BlobSidecarList, Epoch, EthSpec, Hash256, KzgCommitment, + SignedBeaconBlock, SignedBeaconBlockHeader, SignedBlobSidecar, Slot, Transactions, }; -use types::{Epoch, ExecPayload}; #[derive(Debug)] pub enum BlobError { @@ -190,9 +185,9 @@ pub fn validate_blob_sidecar_for_gossip( }; let blob_proposer_index = blob_sidecar.message.proposer_index; - if proposer_index != blob_proposer_index { + if proposer_index != blob_proposer_index as usize { return Err(BlobError::ProposerIndexMismatch { - sidecar: blob_proposer_index, + sidecar: blob_proposer_index as usize, local: proposer_index, }); } @@ -248,7 +243,7 @@ pub fn validate_blob_sidecar_for_gossip( } pub fn verify_data_availability( - blob_sidecar: &BlobsSidecar, + blob_sidecar: &BlobSidecarList, kzg_commitments: &[KzgCommitment], transactions: &Transactions, _block_slot: Slot, @@ -306,36 +301,38 @@ impl IntoAvailableBlock for BlockWrapper { } } -#[derive(Clone, Debug, Derivative)] -#[derivative(PartialEq, Hash(bound = "T: BeaconChainTypes"))] +#[derive(Clone, Debug, PartialEq)] pub struct AvailableBlock { - block: Arc>, - blobs: Blobs, + pub block: Arc>, + pub blobs: Blobs, } impl AvailableBlock { - pub fn blobs(&self) -> Option>> { + pub fn blobs(&self) -> Option>> { match &self.blobs { Blobs::NotRequired | Blobs::None => None, - Blobs::Available(blob_sidecar) => Some(blob_sidecar.clone()), + Blobs::Available(blobs) => Some(blobs.clone()), } } - pub fn deconstruct(self) -> (Arc>, Option>>) { + pub fn deconstruct(self) -> (Arc>, Option>>) { match self.blobs { Blobs::NotRequired | Blobs::None => (self.block, None), - Blobs::Available(blob_sidecars) => (self.block, Some(blob_sidecars)), + Blobs::Available(blobs) => (self.block, Some(blobs)), } } } +#[derive(Clone, Debug, PartialEq)] pub enum Blobs { /// These blobs are available. - Available(VariableList>, E::MaxBlobsPerBlock>), - /// This block is from outside the data availability boundary or the block is from prior - /// to the eip4844 fork. + Available(Arc>), + /// This block is from outside the data availability boundary so doesn't require + /// a data availability check. NotRequired, - /// The block doesn't have any blob transactions. + /// The block's `kzg_commitments` field is empty so it does not contain any blobs. + EmptyBlobs, + /// This is a block prior to the 4844 fork, so doesn't require any blobs None, } @@ -351,59 +348,78 @@ pub trait AsBlock { fn canonical_root(&self) -> Hash256; } +#[derive(Debug, Clone)] +pub enum BlockWrapper { + /// This variant is fully available. + /// i.e. for pre-4844 blocks, it contains a (`SignedBeaconBlock`, `Blobs::None`) and for + /// post-4844 blocks, it contains a `SignedBeaconBlock` and a Blobs variant other than `Blobs::None`. + Available(AvailableBlock), + /// This variant is not fully available and requires blobs to become fully available. + AvailabilityPending(Arc>), +} + +impl BlockWrapper { + pub fn into_available_block(self) -> Option> { + match self { + BlockWrapper::AvailabilityPending(_) => None, + BlockWrapper::Available(block) => Some(block), + } + } +} + impl AsBlock for BlockWrapper { fn slot(&self) -> Slot { match self { - BlockWrapper::Block(block) => block.slot(), - BlockWrapper::BlockAndBlobs(block, _) => block.slot(), + BlockWrapper::Available(block) => block.block.slot(), + BlockWrapper::AvailabilityPending(block) => block.slot(), } } fn epoch(&self) -> Epoch { match self { - BlockWrapper::Block(block) => block.epoch(), - BlockWrapper::BlockAndBlobs(block, _) => block.epoch(), + BlockWrapper::Available(block) => block.block.epoch(), + BlockWrapper::AvailabilityPending(block) => block.epoch(), } } fn parent_root(&self) -> Hash256 { match self { - BlockWrapper::Block(block) => block.parent_root(), - BlockWrapper::BlockAndBlobs(block, _) => block.parent_root(), + BlockWrapper::Available(block) => block.block.parent_root(), + BlockWrapper::AvailabilityPending(block) => block.parent_root(), } } fn state_root(&self) -> Hash256 { match self { - BlockWrapper::Block(block) => block.state_root(), - BlockWrapper::BlockAndBlobs(block, _) => block.state_root(), + BlockWrapper::Available(block) => block.block.state_root(), + BlockWrapper::AvailabilityPending(block) => block.state_root(), } } fn signed_block_header(&self) -> SignedBeaconBlockHeader { match &self { - BlockWrapper::Block(block) => block.signed_block_header(), - BlockWrapper::BlockAndBlobs(block, _) => block.signed_block_header(), + BlockWrapper::Available(block) => block.block.signed_block_header(), + BlockWrapper::AvailabilityPending(block) => block.signed_block_header(), } } fn message(&self) -> BeaconBlockRef { match &self { - BlockWrapper::Block(block) => block.message(), - BlockWrapper::BlockAndBlobs(block, _) => block.message(), + BlockWrapper::Available(block) => block.block.message(), + BlockWrapper::AvailabilityPending(block) => block.message(), } } fn as_block(&self) -> &SignedBeaconBlock { match &self { - BlockWrapper::Block(block) => &block, - BlockWrapper::BlockAndBlobs(block, _) => &block, + BlockWrapper::Available(block) => &block.block, + BlockWrapper::AvailabilityPending(block) => &block, } } fn block_cloned(&self) -> Arc> { match &self { - BlockWrapper::Block(block) => block.clone(), - BlockWrapper::BlockAndBlobs(block, _) => block.clone(), + BlockWrapper::Available(block) => block.block.clone(), + BlockWrapper::AvailabilityPending(block) => block.clone(), } } fn canonical_root(&self) -> Hash256 { match &self { - BlockWrapper::Block(block) => block.canonical_root(), - BlockWrapper::BlockAndBlobs(block, _) => block.canonical_root(), + BlockWrapper::Available(block) => block.block.canonical_root(), + BlockWrapper::AvailabilityPending(block) => block.canonical_root(), } } } @@ -411,91 +427,74 @@ impl AsBlock for BlockWrapper { impl AsBlock for &BlockWrapper { fn slot(&self) -> Slot { match self { - BlockWrapper::Block(block) => block.slot(), - BlockWrapper::BlockAndBlobs(block, _) => block.slot(), + BlockWrapper::Available(block) => block.block.slot(), + BlockWrapper::AvailabilityPending(block) => block.slot(), } } fn epoch(&self) -> Epoch { match self { - BlockWrapper::Block(block) => block.epoch(), - BlockWrapper::BlockAndBlobs(block, _) => block.epoch(), + BlockWrapper::Available(block) => block.block.epoch(), + BlockWrapper::AvailabilityPending(block) => block.epoch(), } } fn parent_root(&self) -> Hash256 { match self { - BlockWrapper::Block(block) => block.parent_root(), - BlockWrapper::BlockAndBlobs(block, _) => block.parent_root(), + BlockWrapper::Available(block) => block.block.parent_root(), + BlockWrapper::AvailabilityPending(block) => block.parent_root(), } } fn state_root(&self) -> Hash256 { match self { - BlockWrapper::Block(block) => block.state_root(), - BlockWrapper::BlockAndBlobs(block, _) => block.state_root(), + BlockWrapper::Available(block) => block.block.state_root(), + BlockWrapper::AvailabilityPending(block) => block.state_root(), } } fn signed_block_header(&self) -> SignedBeaconBlockHeader { match &self { - BlockWrapper::Block(block) => block.signed_block_header(), - BlockWrapper::BlockAndBlobs(block, _) => block.signed_block_header(), + BlockWrapper::Available(block) => block.block.signed_block_header(), + BlockWrapper::AvailabilityPending(block) => block.signed_block_header(), } } fn message(&self) -> BeaconBlockRef { match &self { - BlockWrapper::Block(block) => block.message(), - BlockWrapper::BlockAndBlobs(block, _) => block.message(), + BlockWrapper::Available(block) => block.block.message(), + BlockWrapper::AvailabilityPending(block) => block.message(), } } fn as_block(&self) -> &SignedBeaconBlock { match &self { - BlockWrapper::Block(block) => &block, - BlockWrapper::BlockAndBlobs(block, _) => &block, + BlockWrapper::Available(block) => &block.block, + BlockWrapper::AvailabilityPending(block) => &block, } } fn block_cloned(&self) -> Arc> { match &self { - BlockWrapper::Block(block) => block.clone(), - BlockWrapper::BlockAndBlobs(block, _) => block.clone(), + BlockWrapper::Available(block) => block.block.clone(), + BlockWrapper::AvailabilityPending(block) => block.clone(), } } fn canonical_root(&self) -> Hash256 { match &self { - BlockWrapper::Block(block) => block.canonical_root(), - BlockWrapper::BlockAndBlobs(block, _) => block.canonical_root(), - } - } -} - -/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBeaconBlockAndBlobsSidecar`]. This makes no -/// claims about data availability and should not be used in consensus. This struct is useful in -/// networking when we want to send blocks around without consensus checks. -#[derive(Clone, Debug, Derivative)] -#[derivative(PartialEq, Hash(bound = "E: EthSpec"))] -pub enum BlockWrapper { - Block(Arc>), - BlockAndBlobs(Arc>, Arc>), -} - -impl BlockWrapper { - pub fn new( - block: Arc>, - blobs_sidecar: Option>>, - ) -> Self { - if let Some(blobs_sidecar) = blobs_sidecar { - BlockWrapper::BlockAndBlobs(block, blobs_sidecar) - } else { - BlockWrapper::Block(block) + BlockWrapper::Available(block) => block.block.canonical_root(), + BlockWrapper::AvailabilityPending(block) => block.canonical_root(), } } } impl From> for BlockWrapper { fn from(block: SignedBeaconBlock) -> Self { - BlockWrapper::Block(Arc::new(block)) + BlockWrapper::AvailabilityPending(Arc::new(block)) } } impl From>> for BlockWrapper { fn from(block: Arc>) -> Self { - BlockWrapper::Block(block) + BlockWrapper::AvailabilityPending(block) + } +} + +impl From> for BlockWrapper { + fn from(block: AvailableBlock) -> Self { + BlockWrapper::Available(block) } } diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs index a9e4727ada..544f484663 100644 --- a/beacon_node/beacon_chain/src/block_verification.rs +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -48,9 +48,7 @@ // returned alongside. #![allow(clippy::result_large_err)] -use crate::blob_verification::{ - AsBlock, AvailableBlock, BlobError, BlockWrapper, IntoAvailableBlock, IntoBlockWrapper, -}; +use crate::blob_verification::{AsBlock, AvailableBlock, BlobError, BlockWrapper}; use crate::eth1_finalization_cache::Eth1FinalizationData; use crate::execution_payload::{ is_optimistic_candidate_block, validate_execution_payload_for_gossip, validate_merge_block, @@ -66,7 +64,6 @@ use crate::{ }, metrics, BeaconChain, BeaconChainError, BeaconChainTypes, }; -use derivative::Derivative; use eth2::types::EventKind; use execution_layer::PayloadStatus; use fork_choice::{AttestationFromBlock, PayloadVerificationStatus}; @@ -595,13 +592,12 @@ pub fn signature_verify_chain_segment( signature_verifier.include_all_signatures(block.as_block(), &mut consensus_context)?; //FIXME(sean) batch kzg verification - let available_block = block.clone().into_available_block(*block_root, chain)?; consensus_context = consensus_context.set_kzg_commitments_consistent(true); // Save the block and its consensus context. The context will have had its proposer index // and attesting indices filled in, which can be used to accelerate later block processing. signature_verified_blocks.push(SignatureVerifiedBlock { - block: available_block, + block: block.clone(), block_root: *block_root, parent: None, consensus_context, @@ -623,10 +619,9 @@ pub fn signature_verify_chain_segment( /// A wrapper around a `SignedBeaconBlock` that indicates it has been approved for re-gossiping on /// the p2p network. -#[derive(Derivative)] -#[derivative(Debug(bound = "T: BeaconChainTypes"))] +#[derive(Debug)] pub struct GossipVerifiedBlock { - pub block: Arc>, + pub block: BlockWrapper, pub block_root: Hash256, parent: Option>, consensus_context: ConsensusContext, @@ -635,7 +630,7 @@ pub struct GossipVerifiedBlock { /// A wrapper around a `SignedBeaconBlock` that indicates that all signatures (except the deposit /// signatures) have been verified. pub struct SignatureVerifiedBlock { - block: Arc>, + block: BlockWrapper, block_root: Hash256, parent: Option>, consensus_context: ConsensusContext, @@ -658,7 +653,7 @@ type PayloadVerificationHandle = /// due to finality or some other event. A `ExecutionPendingBlock` should be imported into the /// `BeaconChain` immediately after it is instantiated. pub struct ExecutionPendingBlock { - pub block: Arc>, + pub block: BlockWrapper, pub block_root: Hash256, pub state: BeaconState, pub parent_block: SignedBeaconBlock>, @@ -669,7 +664,7 @@ pub struct ExecutionPendingBlock { } pub struct ExecutedBlock { - pub block: Arc>, + pub block: BlockWrapper, pub block_root: Hash256, pub state: BeaconState, pub parent_block: SignedBeaconBlock>, @@ -930,13 +925,13 @@ impl GossipVerifiedBlock { validate_execution_payload_for_gossip(&parent_block, block.message(), chain)?; // Having checked the proposer index and the block root we can cache them. - let consensus_context = ConsensusContext::new(available_block.slot()) + let consensus_context = ConsensusContext::new(block.slot()) .set_current_block_root(block_root) .set_proposer_index(block.as_block().message().proposer_index()) .set_kzg_commitments_consistent(true); Ok(Self { - block: available_block, + block: block, block_root, parent, consensus_context, @@ -966,7 +961,7 @@ impl IntoExecutionPendingBlock for GossipVerifiedBlock &SignedBeaconBlock { - self.block.as_ref() + self.block.as_block() } } @@ -980,6 +975,7 @@ impl SignatureVerifiedBlock { block_root: Hash256, chain: &BeaconChain, ) -> Result> { + let block = BlockWrapper::from(block); // Ensure the block is the correct structure for the fork at `block.slot()`. block .as_block() @@ -1118,7 +1114,7 @@ impl IntoExecutionPendingBlock for SignatureVerifiedBloc } fn block(&self) -> &SignedBeaconBlock { - self.block.as_ref() + self.block.as_block() } } @@ -1136,11 +1132,8 @@ impl IntoExecutionPendingBlock for Arc IntoExecutionPendingBlock for Arc IntoExecutionPendingBlock for BlockWrapper { + fn into_execution_pending_block_slashable( + self, + block_root: Hash256, + chain: &Arc>, + notify_execution_layer: NotifyExecutionLayer, + ) -> Result< + ExecutionPendingBlock, + BlockSlashInfo::EthSpec>>, + > { + match self { + BlockWrapper::AvailabilityPending(block) => block + .into_execution_pending_block_slashable(block_root, chain, notify_execution_layer), + BlockWrapper::Available(AvailableBlock { block, blobs }) => { + let execution_pending_block = block.into_execution_pending_block_slashable( + block_root, + chain, + notify_execution_layer, + )?; + let block = execution_pending_block.block.block_cloned(); + let available_execution_pending_block = + BlockWrapper::Available(AvailableBlock { block, blobs }); + std::mem::replace( + &mut execution_pending_block.block, + available_execution_pending_block, + ); + Ok(execution_pending_block) + } + } + } + + fn block(&self) -> &SignedBeaconBlock<::EthSpec> { + self.as_block() + } +} + impl ExecutionPendingBlock { /// Instantiates `Self`, a wrapper that indicates that the given `block` is fully valid. See /// the struct-level documentation for more information. @@ -1158,7 +1187,7 @@ impl ExecutionPendingBlock { /// /// Returns an error if the block is invalid, or if the block was unable to be verified. pub fn from_signature_verified_components( - block: Arc>, + block: BlockWrapper, block_root: Hash256, parent: PreProcessingSnapshot, mut consensus_context: ConsensusContext, @@ -1188,7 +1217,7 @@ impl ExecutionPendingBlock { // because it will revert finalization. Note that the finalized block is stored in fork // choice, so we will not reject any child of the finalized block (this is relevant during // genesis). - return Err(BlockError::ParentUnknown(block.into_block_wrapper())); + return Err(BlockError::ParentUnknown(block)); } // Reject any block that exceeds our limit on skipped slots. @@ -1623,14 +1652,11 @@ fn check_block_against_finalized_slot( /// ## Warning /// /// Taking a lock on the `chain.canonical_head.fork_choice` might cause a deadlock here. -pub fn check_block_is_finalized_checkpoint_or_descendant< - T: BeaconChainTypes, - B: IntoBlockWrapper, ->( +pub fn check_block_is_finalized_checkpoint_or_descendant( chain: &BeaconChain, fork_choice: &BeaconForkChoice, - block: B, -) -> Result> { + block: BlockWrapper, +) -> Result, BlockError> { if fork_choice.is_finalized_checkpoint_or_descendant(block.parent_root()) { Ok(block) } else { @@ -1651,7 +1677,7 @@ pub fn check_block_is_finalized_checkpoint_or_descendant< block_parent_root: block.parent_root(), }) } else { - Err(BlockError::ParentUnknown(block.into_block_wrapper())) + Err(BlockError::ParentUnknown(block)) } } } @@ -1741,11 +1767,11 @@ fn verify_parent_block_is_known( /// Returns `Err(BlockError::ParentUnknown)` if the parent is not found, or if an error occurs /// whilst attempting the operation. #[allow(clippy::type_complexity)] -fn load_parent>( +fn load_parent( block_root: Hash256, - block: B, + block: BlockWrapper, chain: &BeaconChain, -) -> Result<(PreProcessingSnapshot, B), BlockError> { +) -> Result<(PreProcessingSnapshot, BlockWrapper), BlockError> { let spec = &chain.spec; // Reject any block if its parent is not known to fork choice. @@ -1763,7 +1789,7 @@ fn load_parent>( .fork_choice_read_lock() .contains_block(&block.parent_root()) { - return Err(BlockError::ParentUnknown(block.into_block_wrapper())); + return Err(BlockError::ParentUnknown(block)); } let block_delay = chain diff --git a/consensus/types/src/signed_blob.rs b/consensus/types/src/signed_blob.rs index 4121b8b7f2..c295f6c6c1 100644 --- a/consensus/types/src/signed_blob.rs +++ b/consensus/types/src/signed_blob.rs @@ -1,4 +1,7 @@ -use crate::{test_utils::TestRandom, BlobSidecar, EthSpec, Signature}; +use crate::{ + test_utils::TestRandom, BlobSidecar, ChainSpec, EthSpec, Fork, Hash256, PublicKey, Signature, + SignedRoot, +}; use derivative::Derivative; use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; @@ -25,3 +28,19 @@ pub struct SignedBlobSidecar { pub message: BlobSidecar, pub signature: Signature, } + +impl SignedRoot for SignedBlobSidecar {} + +impl SignedBlobSidecar { + pub fn verify_signature( + &self, + _object_root_opt: Option, + _pubkey: &PublicKey, + _fork: &Fork, + _genesis_validators_root: Hash256, + _spec: &ChainSpec, + ) -> bool { + // TODO (pawan): fill up logic + unimplemented!() + } +}