@@ -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,
@@ -3094,6 +3130,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
30943130 . beacon_state
30953131 . attester_shuffling_decision_root ( self . genesis_block_root , RelativeEpoch :: Current ) ;
30963132
3133+ // Used later for the execution engine.
3134+ let new_head_execution_block_hash = new_head
3135+ . beacon_block
3136+ . message ( )
3137+ . body ( )
3138+ . execution_payload ( )
3139+ . map ( |ep| ep. block_hash ) ;
3140+
30973141 drop ( lag_timer) ;
30983142
30993143 // Update the snapshot that stores the head of the chain at the time it received the
@@ -3297,9 +3341,67 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
32973341 }
32983342 }
32993343
3344+ // If this is a post-merge block, update the execution layer.
3345+ if let Some ( new_head_execution_block_hash) = new_head_execution_block_hash {
3346+ let execution_layer = self
3347+ . execution_layer
3348+ . clone ( )
3349+ . ok_or ( Error :: ExecutionLayerMissing ) ?;
3350+ let store = self . store . clone ( ) ;
3351+ let log = self . log . clone ( ) ;
3352+
3353+ // Spawn the update task, without waiting for it to complete.
3354+ execution_layer. spawn (
3355+ move |execution_layer| async move {
3356+ if let Err ( e) = Self :: update_execution_engine_forkchoice (
3357+ execution_layer,
3358+ store,
3359+ new_finalized_checkpoint. root ,
3360+ new_head_execution_block_hash,
3361+ )
3362+ . await
3363+ {
3364+ error ! (
3365+ log,
3366+ "Failed to update execution head" ;
3367+ "error" => ?e
3368+ ) ;
3369+ }
3370+ } ,
3371+ "update_execution_engine_forkchoice" ,
3372+ )
3373+ }
3374+
33003375 Ok ( ( ) )
33013376 }
33023377
3378+ pub async fn update_execution_engine_forkchoice (
3379+ execution_layer : ExecutionLayer ,
3380+ store : BeaconStore < T > ,
3381+ finalized_beacon_block_root : Hash256 ,
3382+ head_execution_block_hash : Hash256 ,
3383+ ) -> Result < ( ) , Error > {
3384+ // Loading the finalized block from the store is not ideal. Perhaps it would be better to
3385+ // store it on fork-choice so we can do a lookup without hitting the database.
3386+ //
3387+ // See: https://github.com/sigp/lighthouse/pull/2627#issuecomment-927537245
3388+ let finalized_block = store
3389+ . get_block ( & finalized_beacon_block_root) ?
3390+ . ok_or ( Error :: MissingBeaconBlock ( finalized_beacon_block_root) ) ?;
3391+
3392+ let finalized_execution_block_hash = finalized_block
3393+ . message ( )
3394+ . body ( )
3395+ . execution_payload ( )
3396+ . map ( |ep| ep. block_hash )
3397+ . unwrap_or_else ( Hash256 :: zero) ;
3398+
3399+ execution_layer
3400+ . forkchoice_updated ( head_execution_block_hash, finalized_execution_block_hash)
3401+ . await
3402+ . map_err ( Error :: ExecutionForkChoiceUpdateFailed )
3403+ }
3404+
33033405 /// This function takes a configured weak subjectivity `Checkpoint` and the latest finalized `Checkpoint`.
33043406 /// If the weak subjectivity checkpoint and finalized checkpoint share the same epoch, we compare
33053407 /// roots. If we the weak subjectivity checkpoint is from an older epoch, we iterate back through
0 commit comments