@@ -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.
@@ -2407,7 +2412,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
24072412 let _fork_choice_block_timer =
24082413 metrics:: start_timer ( & metrics:: FORK_CHOICE_PROCESS_BLOCK_TIMES ) ;
24092414 fork_choice
2410- . on_block ( current_slot, & block, block_root, & state, & self . spec )
2415+ . on_block ( current_slot, & block, block_root, & state)
24112416 . map_err ( |e| BlockError :: BeaconChainError ( e. into ( ) ) ) ?;
24122417 }
24132418
@@ -2839,12 +2844,42 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
28392844 } ) )
28402845 } ;
28412846 // Closure to fetch a sync aggregate in cases where it is required.
2842- let get_execution_payload = || -> Result < ExecutionPayload < _ > , BlockProductionError > {
2843- // TODO: actually get the payload from eth1 node..
2844- Ok ( ExecutionPayload :: default ( ) )
2847+ let get_execution_payload = |latest_execution_payload_header : & ExecutionPayloadHeader <
2848+ T :: EthSpec ,
2849+ > |
2850+ -> Result < ExecutionPayload < _ > , BlockProductionError > {
2851+ let execution_layer = self
2852+ . execution_layer
2853+ . as_ref ( )
2854+ . ok_or ( BlockProductionError :: ExecutionLayerMissing ) ?;
2855+
2856+ let parent_hash;
2857+ if !is_merge_complete ( & state) {
2858+ let terminal_pow_block_hash = execution_layer
2859+ . block_on ( |execution_layer| execution_layer. get_terminal_pow_block_hash ( ) )
2860+ . map_err ( BlockProductionError :: TerminalPoWBlockLookupFailed ) ?;
2861+
2862+ if let Some ( terminal_pow_block_hash) = terminal_pow_block_hash {
2863+ parent_hash = terminal_pow_block_hash;
2864+ } else {
2865+ return Ok ( <_ >:: default ( ) ) ;
2866+ }
2867+ } else {
2868+ parent_hash = latest_execution_payload_header. block_hash ;
2869+ }
2870+
2871+ let timestamp =
2872+ compute_timestamp_at_slot ( & state, & self . spec ) . map_err ( BeaconStateError :: from) ?;
2873+ let random = * state. get_randao_mix ( state. current_epoch ( ) ) ?;
2874+
2875+ execution_layer
2876+ . block_on ( |execution_layer| {
2877+ execution_layer. get_payload ( parent_hash, timestamp, random)
2878+ } )
2879+ . map_err ( BlockProductionError :: GetPayloadFailed )
28452880 } ;
28462881
2847- let inner_block = match state {
2882+ let inner_block = match & state {
28482883 BeaconState :: Base ( _) => BeaconBlock :: Base ( BeaconBlockBase {
28492884 slot,
28502885 proposer_index,
@@ -2881,9 +2916,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
28812916 } ,
28822917 } )
28832918 }
2884- BeaconState :: Merge ( _ ) => {
2919+ BeaconState :: Merge ( state ) => {
28852920 let sync_aggregate = get_sync_aggregate ( ) ?;
2886- let execution_payload = get_execution_payload ( ) ?;
2921+ let execution_payload =
2922+ get_execution_payload ( & state. latest_execution_payload_header ) ?;
28872923 BeaconBlock :: Merge ( BeaconBlockMerge {
28882924 slot,
28892925 proposer_index,
@@ -3093,6 +3129,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
30933129 . graffiti ( )
30943130 . as_utf8_lossy ( ) ;
30953131
3132+ // Used later for the execution engine.
3133+ let new_head_execution_block_hash = new_head
3134+ . beacon_block
3135+ . message ( )
3136+ . body ( )
3137+ . execution_payload ( )
3138+ . map ( |ep| ep. block_hash ) ;
3139+
30963140 drop ( lag_timer) ;
30973141
30983142 // Update the snapshot that stores the head of the chain at the time it received the
@@ -3303,9 +3347,67 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
33033347 }
33043348 }
33053349
3350+ // If this is a post-merge block, update the execution layer.
3351+ if let Some ( new_head_execution_block_hash) = new_head_execution_block_hash {
3352+ let execution_layer = self
3353+ . execution_layer
3354+ . clone ( )
3355+ . ok_or ( Error :: ExecutionLayerMissing ) ?;
3356+ let store = self . store . clone ( ) ;
3357+ let log = self . log . clone ( ) ;
3358+
3359+ // Spawn the update task, without waiting for it to complete.
3360+ execution_layer. spawn (
3361+ move |execution_layer| async move {
3362+ if let Err ( e) = Self :: update_execution_engine_forkchoice (
3363+ execution_layer,
3364+ store,
3365+ new_finalized_checkpoint. root ,
3366+ new_head_execution_block_hash,
3367+ )
3368+ . await
3369+ {
3370+ error ! (
3371+ log,
3372+ "Failed to update execution head" ;
3373+ "error" => ?e
3374+ ) ;
3375+ }
3376+ } ,
3377+ "update_execution_engine_forkchoice" ,
3378+ )
3379+ }
3380+
33063381 Ok ( ( ) )
33073382 }
33083383
3384+ pub async fn update_execution_engine_forkchoice (
3385+ execution_layer : ExecutionLayer ,
3386+ store : BeaconStore < T > ,
3387+ finalized_beacon_block_root : Hash256 ,
3388+ head_execution_block_hash : Hash256 ,
3389+ ) -> Result < ( ) , Error > {
3390+ // Loading the finalized block from the store is not ideal. Perhaps it would be better to
3391+ // store it on fork-choice so we can do a lookup without hitting the database.
3392+ //
3393+ // See: https://github.com/sigp/lighthouse/pull/2627#issuecomment-927537245
3394+ let finalized_block = store
3395+ . get_block ( & finalized_beacon_block_root) ?
3396+ . ok_or ( Error :: MissingBeaconBlock ( finalized_beacon_block_root) ) ?;
3397+
3398+ let finalized_execution_block_hash = finalized_block
3399+ . message ( )
3400+ . body ( )
3401+ . execution_payload ( )
3402+ . map ( |ep| ep. block_hash )
3403+ . unwrap_or_else ( Hash256 :: zero) ;
3404+
3405+ execution_layer
3406+ . forkchoice_updated ( head_execution_block_hash, finalized_execution_block_hash)
3407+ . await
3408+ . map_err ( Error :: ExecutionForkChoiceUpdateFailed )
3409+ }
3410+
33093411 /// This function takes a configured weak subjectivity `Checkpoint` and the latest finalized `Checkpoint`.
33103412 /// If the weak subjectivity checkpoint and finalized checkpoint share the same epoch, we compare
33113413 /// roots. If we the weak subjectivity checkpoint is from an older epoch, we iterate back through
0 commit comments