Skip to content

Commit 3f45ad0

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 796f0c2 commit 3f45ad0

File tree

38 files changed

+3240
-115
lines changed

38 files changed

+3240
-115
lines changed

Cargo.lock

Lines changed: 0 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/lighthouse_network",
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 @@ slasher = { path = "../../slasher" }
5555
eth2 = { path = "../../common/eth2" }
5656
strum = { version = "0.21.0", features = ["derive"] }
5757
logging = { path = "../../common/logging" }
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.
@@ -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

Comments
 (0)