Skip to content

Commit a264ccf

Browse files
[Merge] Implement execution_layer (#2635)
* Checkout serde_utils from rayonism * Make eth1::http functions pub * Add bones of execution_layer * Modify decoding * Expose Transaction, cargo fmt * Add executePayload * Add all minimal spec endpoints * Start adding json rpc wrapper * Finish custom JSON response handler * Switch to new rpc sending method * Add first test * Fix camelCase * Finish adding tests * Begin threading execution layer into BeaconChain * Fix clippy lints * Fix clippy lints * Thread execution layer into ClientBuilder * Add CLI flags * Add block processing methods to ExecutionLayer * Add block_on to execution_layer * Integrate execute_payload * Add extra_data field * Begin implementing payload handle * Send consensus valid/invalid messages * Fix minor type in task_executor * Call forkchoiceUpdated * Add search for TTD block * Thread TTD into execution layer * Allow producing block with execution payload * Add LRU cache for execution blocks * Remove duplicate 0x on ssz_types serialization * Add tests for block getter methods * Add basic block generator impl * Add is_valid_terminal_block to EL * Verify merge block in block_verification * Partially implement --terminal-block-hash-override * Add terminal_block_hash to ChainSpec * Remove Option from terminal_block_hash in EL * Revert merge changes to consensus/fork_choice * Remove commented-out code * Add bones for handling RPC methods on test server * Add first ExecutionLayer tests * Add testing for finding terminal block * Prevent infinite loops * Add insert_merge_block to block gen * Add block gen test for pos blocks * Start adding payloads to block gen * Fix clippy lints * Add execution payload to block gen * Add execute_payload to block_gen * Refactor block gen * Add all routes to mock server * Use Uint256 for base_fee_per_gas * Add working execution chain build * Remove unused var * Revert "Use Uint256 for base_fee_per_gas" This reverts commit 6c88f19. * Fix base_fee_for_gas Uint256 * Update execute payload handle * Improve testing, fix bugs * Fix default fee-recipient * Fix fee-recipient address (again) * Add check for terminal block, add comments, tidy * Apply suggestions from code review Co-authored-by: realbigsean <[email protected]> * Fix is_none on handle Drop * Remove commented-out tests Co-authored-by: realbigsean <[email protected]>
1 parent a5127fb commit a264ccf

File tree

38 files changed

+3269
-115
lines changed

38 files changed

+3269
-115
lines changed

Cargo.lock

Lines changed: 29 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ members = [
77
"beacon_node/client",
88
"beacon_node/eth1",
99
"beacon_node/eth2_libp2p",
10+
"beacon_node/execution_layer",
1011
"beacon_node/http_api",
1112
"beacon_node/http_metrics",
1213
"beacon_node/network",

beacon_node/beacon_chain/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@ itertools = "0.10.0"
5555
slasher = { path = "../../slasher" }
5656
eth2 = { path = "../../common/eth2" }
5757
strum = { version = "0.21.0", features = ["derive"] }
58+
execution_layer = { path = "../execution_layer" }

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 110 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ use crate::{metrics, BeaconChainError};
4949
use eth2::types::{
5050
EventKind, SseBlock, SseChainReorg, SseFinalizedCheckpoint, SseHead, SseLateHead, SyncDuty,
5151
};
52+
use execution_layer::ExecutionLayer;
5253
use fork_choice::ForkChoice;
5354
use futures::channel::mpsc::Sender;
5455
use itertools::process_results;
@@ -62,7 +63,9 @@ use slot_clock::SlotClock;
6263
use 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

Comments
 (0)