@@ -194,6 +194,7 @@ pub struct HeadInfo {
194194 pub genesis_time : u64 ,
195195 pub genesis_validators_root : Hash256 ,
196196 pub proposer_shuffling_decision_root : Hash256 ,
197+ pub is_merge_complete : bool ,
197198}
198199
199200pub trait BeaconChainTypes : Send + Sync + ' static {
@@ -204,6 +205,19 @@ pub trait BeaconChainTypes: Send + Sync + 'static {
204205 type EthSpec : types:: EthSpec ;
205206}
206207
208+ /// Indicates the status of the `ExecutionLayer`.
209+ #[ derive( Debug , PartialEq ) ]
210+ pub enum ExecutionLayerStatus {
211+ /// The execution layer is synced and reachable.
212+ Ready ,
213+ /// The execution layer either syncing or unreachable.
214+ NotReady ,
215+ /// The execution layer is required, but has not been enabled. This is a configuration error.
216+ Missing ,
217+ /// The execution layer is not yet required, therefore the status is irrelevant.
218+ NotRequired ,
219+ }
220+
207221pub type BeaconForkChoice < T > = ForkChoice <
208222 BeaconForkChoiceStore <
209223 <T as BeaconChainTypes >:: EthSpec ,
@@ -1001,6 +1015,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
10011015 genesis_time : head. beacon_state . genesis_time ( ) ,
10021016 genesis_validators_root : head. beacon_state . genesis_validators_root ( ) ,
10031017 proposer_shuffling_decision_root,
1018+ is_merge_complete : is_merge_complete ( & head. beacon_state ) ,
10041019 } )
10051020 } )
10061021 }
@@ -3405,6 +3420,39 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
34053420 . map_err ( Error :: ExecutionForkChoiceUpdateFailed )
34063421 }
34073422
3423+ /// Indicates the status of the execution layer.
3424+ pub async fn execution_layer_status ( & self ) -> Result < ExecutionLayerStatus , BeaconChainError > {
3425+ let epoch = self . epoch ( ) ?;
3426+ if self . spec . merge_fork_epoch . map_or ( true , |fork| epoch < fork) {
3427+ return Ok ( ExecutionLayerStatus :: NotRequired ) ;
3428+ }
3429+
3430+ if let Some ( execution_layer) = & self . execution_layer {
3431+ if execution_layer. is_synced ( ) . await {
3432+ Ok ( ExecutionLayerStatus :: Ready )
3433+ } else {
3434+ Ok ( ExecutionLayerStatus :: NotReady )
3435+ }
3436+ } else {
3437+ // This branch is slightly more restrictive than what is minimally required.
3438+ //
3439+ // It is possible for a node without an execution layer (EL) to follow the chain
3440+ // *after* the merge fork and *before* the terminal execution block, as long as
3441+ // that node is not required to produce blocks.
3442+ //
3443+ // However, here we say that all nodes *must* have an EL as soon as the merge fork
3444+ // happens. We do this because it's very difficult to determine that the terminal
3445+ // block has been met if we don't already have an EL. As far as we know, the
3446+ // terminal execution block might already exist and we've been rejecting it since
3447+ // we don't have an EL to verify it.
3448+ //
3449+ // I think it is very reasonable to say that the beacon chain expects all BNs to
3450+ // be paired with an EL node by the time the merge fork epoch is reached. So, we
3451+ // enforce that here.
3452+ Ok ( ExecutionLayerStatus :: Missing )
3453+ }
3454+ }
3455+
34083456 /// This function takes a configured weak subjectivity `Checkpoint` and the latest finalized `Checkpoint`.
34093457 /// If the weak subjectivity checkpoint and finalized checkpoint share the same epoch, we compare
34103458 /// roots. If we the weak subjectivity checkpoint is from an older epoch, we iterate back through
0 commit comments