@@ -49,6 +49,7 @@ use crate::{metrics, BeaconChainError};
4949use eth2:: types:: {
5050 EventKind , SseBlock , SseChainReorg , SseFinalizedCheckpoint , SseHead , SseLateHead , SyncDuty ,
5151} ;
52+ use execution_layer:: ExecutionLayer ;
5253use fork_choice:: ForkChoice ;
5354use futures:: channel:: mpsc:: Sender ;
5455use itertools:: process_results;
@@ -62,7 +63,9 @@ use slot_clock::SlotClock;
6263use state_processing:: {
6364 common:: get_indexed_attestation,
6465 per_block_processing,
65- per_block_processing:: errors:: AttestationValidationError ,
66+ per_block_processing:: {
67+ compute_timestamp_at_slot, errors:: AttestationValidationError , is_merge_complete,
68+ } ,
6669 per_slot_processing,
6770 state_advance:: { complete_state_advance, partial_state_advance} ,
6871 BlockSignatureStrategy , SigVerifiedOp ,
@@ -275,6 +278,8 @@ pub struct BeaconChain<T: BeaconChainTypes> {
275278 Mutex < ObservedOperations < AttesterSlashing < T :: EthSpec > , T :: EthSpec > > ,
276279 /// Provides information from the Ethereum 1 (PoW) chain.
277280 pub eth1_chain : Option < Eth1Chain < T :: Eth1Chain , T :: EthSpec > > ,
281+ /// Interfaces with the execution client.
282+ pub execution_layer : Option < ExecutionLayer > ,
278283 /// Stores a "snapshot" of the chain at the time the head-of-the-chain block was received.
279284 pub ( crate ) canonical_head : TimeoutRwLock < BeaconSnapshot < T :: EthSpec > > ,
280285 /// The root of the genesis block.
@@ -2390,7 +2395,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
23902395 let _fork_choice_block_timer =
23912396 metrics:: start_timer ( & metrics:: FORK_CHOICE_PROCESS_BLOCK_TIMES ) ;
23922397 fork_choice
2393- . on_block ( current_slot, & block, block_root, & state, & self . spec )
2398+ . on_block ( current_slot, & block, block_root, & state)
23942399 . map_err ( |e| BlockError :: BeaconChainError ( e. into ( ) ) ) ?;
23952400 }
23962401
@@ -2822,12 +2827,42 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
28222827 } ) )
28232828 } ;
28242829 // Closure to fetch a sync aggregate in cases where it is required.
2825- let get_execution_payload = || -> Result < ExecutionPayload < _ > , BlockProductionError > {
2826- // TODO: actually get the payload from eth1 node..
2827- Ok ( ExecutionPayload :: default ( ) )
2830+ let get_execution_payload = |latest_execution_payload_header : & ExecutionPayloadHeader <
2831+ T :: EthSpec ,
2832+ > |
2833+ -> Result < ExecutionPayload < _ > , BlockProductionError > {
2834+ let execution_layer = self
2835+ . execution_layer
2836+ . as_ref ( )
2837+ . ok_or ( BlockProductionError :: ExecutionLayerMissing ) ?;
2838+
2839+ let parent_hash;
2840+ if !is_merge_complete ( & state) {
2841+ let terminal_pow_block_hash = execution_layer
2842+ . block_on ( |execution_layer| execution_layer. get_terminal_pow_block_hash ( ) )
2843+ . map_err ( BlockProductionError :: TerminalPoWBlockLookupFailed ) ?;
2844+
2845+ if let Some ( terminal_pow_block_hash) = terminal_pow_block_hash {
2846+ parent_hash = terminal_pow_block_hash;
2847+ } else {
2848+ return Ok ( <_ >:: default ( ) ) ;
2849+ }
2850+ } else {
2851+ parent_hash = latest_execution_payload_header. block_hash ;
2852+ }
2853+
2854+ let timestamp =
2855+ compute_timestamp_at_slot ( & state, & self . spec ) . map_err ( BeaconStateError :: from) ?;
2856+ let random = * state. get_randao_mix ( state. current_epoch ( ) ) ?;
2857+
2858+ execution_layer
2859+ . block_on ( |execution_layer| {
2860+ execution_layer. get_payload ( parent_hash, timestamp, random)
2861+ } )
2862+ . map_err ( BlockProductionError :: GetPayloadFailed )
28282863 } ;
28292864
2830- let inner_block = match state {
2865+ let inner_block = match & state {
28312866 BeaconState :: Base ( _) => BeaconBlock :: Base ( BeaconBlockBase {
28322867 slot,
28332868 proposer_index,
@@ -2864,9 +2899,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
28642899 } ,
28652900 } )
28662901 }
2867- BeaconState :: Merge ( _ ) => {
2902+ BeaconState :: Merge ( state ) => {
28682903 let sync_aggregate = get_sync_aggregate ( ) ?;
2869- let execution_payload = get_execution_payload ( ) ?;
2904+ let execution_payload =
2905+ get_execution_payload ( & state. latest_execution_payload_header ) ?;
28702906 BeaconBlock :: Merge ( BeaconBlockMerge {
28712907 slot,
28722908 proposer_index,
@@ -3076,6 +3112,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
30763112 . graffiti ( )
30773113 . as_utf8_lossy ( ) ;
30783114
3115+ // Used later for the execution engine.
3116+ let new_head_execution_block_hash = new_head
3117+ . beacon_block
3118+ . message ( )
3119+ . body ( )
3120+ . execution_payload ( )
3121+ . map ( |ep| ep. block_hash ) ;
3122+
30793123 drop ( lag_timer) ;
30803124
30813125 // Update the snapshot that stores the head of the chain at the time it received the
@@ -3286,9 +3330,67 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
32863330 }
32873331 }
32883332
3333+ // If this is a post-merge block, update the execution layer.
3334+ if let Some ( new_head_execution_block_hash) = new_head_execution_block_hash {
3335+ let execution_layer = self
3336+ . execution_layer
3337+ . clone ( )
3338+ . ok_or ( Error :: ExecutionLayerMissing ) ?;
3339+ let store = self . store . clone ( ) ;
3340+ let log = self . log . clone ( ) ;
3341+
3342+ // Spawn the update task, without waiting for it to complete.
3343+ execution_layer. spawn (
3344+ move |execution_layer| async move {
3345+ if let Err ( e) = Self :: update_execution_engine_forkchoice (
3346+ execution_layer,
3347+ store,
3348+ new_finalized_checkpoint. root ,
3349+ new_head_execution_block_hash,
3350+ )
3351+ . await
3352+ {
3353+ error ! (
3354+ log,
3355+ "Failed to update execution head" ;
3356+ "error" => ?e
3357+ ) ;
3358+ }
3359+ } ,
3360+ "update_execution_engine_forkchoice" ,
3361+ )
3362+ }
3363+
32893364 Ok ( ( ) )
32903365 }
32913366
3367+ pub async fn update_execution_engine_forkchoice (
3368+ execution_layer : ExecutionLayer ,
3369+ store : BeaconStore < T > ,
3370+ finalized_beacon_block_root : Hash256 ,
3371+ head_execution_block_hash : Hash256 ,
3372+ ) -> Result < ( ) , Error > {
3373+ // Loading the finalized block from the store is not ideal. Perhaps it would be better to
3374+ // store it on fork-choice so we can do a lookup without hitting the database.
3375+ //
3376+ // See: https://github.com/sigp/lighthouse/pull/2627#issuecomment-927537245
3377+ let finalized_block = store
3378+ . get_block ( & finalized_beacon_block_root) ?
3379+ . ok_or ( Error :: MissingBeaconBlock ( finalized_beacon_block_root) ) ?;
3380+
3381+ let finalized_execution_block_hash = finalized_block
3382+ . message ( )
3383+ . body ( )
3384+ . execution_payload ( )
3385+ . map ( |ep| ep. block_hash )
3386+ . unwrap_or_else ( Hash256 :: zero) ;
3387+
3388+ execution_layer
3389+ . forkchoice_updated ( head_execution_block_hash, finalized_execution_block_hash)
3390+ . await
3391+ . map_err ( Error :: ExecutionForkChoiceUpdateFailed )
3392+ }
3393+
32923394 /// This function takes a configured weak subjectivity `Checkpoint` and the latest finalized `Checkpoint`.
32933395 /// If the weak subjectivity checkpoint and finalized checkpoint share the same epoch, we compare
32943396 /// roots. If we the weak subjectivity checkpoint is from an older epoch, we iterate back through
0 commit comments