Implement engine API v1.0.0-alpha.4 (#2810)

* Added ForkchoiceUpdatedV1 & GetPayloadV1

* Added ExecutePayloadV1

* Added new geth test vectors

* Separated Json Object/Serialization Code into file

* Deleted code/tests for Requests Removed from spec

* Finally fixed serialization of null '0x'

* Made Naming of JSON Structs Consistent

* Fix clippy lints

* Remove u64 payload id

* Remove unused serde impls

* Swap to [u8; 8] for payload id

* Tidy

* Adjust some block gen return vals

* Tidy

* Add fallback when payload id is unknown

* Remove comment

Co-authored-by: Mark Mackey <mark@sigmaprime.io>
This commit is contained in:
Paul Hauner
2021-11-15 17:13:38 +11:00
parent cdfd1304a5
commit 47db682d7e
17 changed files with 1271 additions and 915 deletions

View File

@@ -2908,10 +2908,30 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let timestamp =
compute_timestamp_at_slot(&state, &self.spec).map_err(BeaconStateError::from)?;
let random = *state.get_randao_mix(state.current_epoch())?;
let finalized_root = state.finalized_checkpoint().root;
let finalized_block_hash =
if let Some(block) = self.fork_choice.read().get_block(&finalized_root) {
block.execution_status.block_hash()
} else {
self.store
.get_block(&finalized_root)
.map_err(BlockProductionError::FailedToReadFinalizedBlock)?
.ok_or(BlockProductionError::MissingFinalizedBlock(finalized_root))?
.message()
.body()
.execution_payload()
.map(|ep| ep.block_hash)
};
execution_layer
.block_on(|execution_layer| {
execution_layer.get_payload(parent_hash, timestamp, random)
execution_layer.get_payload(
parent_hash,
timestamp,
random,
finalized_block_hash.unwrap_or_else(Hash256::zero),
)
})
.map_err(BlockProductionError::GetPayloadFailed)
};
@@ -3168,7 +3188,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.attester_shuffling_decision_root(self.genesis_block_root, RelativeEpoch::Current);
// Used later for the execution engine.
let new_head_execution_block_hash = new_head
let new_head_execution_block_hash_opt = new_head
.beacon_block
.message()
.body()
@@ -3404,7 +3424,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}
// If this is a post-merge block, update the execution layer.
if let Some(block_hash) = new_head_execution_block_hash {
if let Some(new_head_execution_block_hash) = new_head_execution_block_hash_opt {
if is_merge_complete {
let execution_layer = self
.execution_layer
@@ -3420,7 +3440,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
execution_layer,
store,
new_finalized_checkpoint.root,
block_hash,
new_head_execution_block_hash,
)
.await
{
@@ -3461,7 +3481,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.unwrap_or_else(Hash256::zero);
execution_layer
.forkchoice_updated(head_execution_block_hash, finalized_execution_block_hash)
.notify_forkchoice_updated(
head_execution_block_hash,
finalized_execution_block_hash,
None,
)
.await
.map_err(Error::ExecutionForkChoiceUpdateFailed)
}

View File

@@ -50,7 +50,7 @@ use crate::{
},
metrics, BeaconChain, BeaconChainError, BeaconChainTypes,
};
use execution_layer::ExecutePayloadResponse;
use execution_layer::ExecutePayloadResponseStatus;
use fork_choice::{ForkChoice, ForkChoiceStore, PayloadVerificationStatus};
use parking_lot::RwLockReadGuard;
use proto_array::{Block as ProtoBlock, ExecutionStatus};
@@ -1139,7 +1139,9 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
}
// This is the soonest we can run these checks as they must be called AFTER per_slot_processing
let (execute_payload_handle, payload_verification_status) =
//
// TODO(merge): handle the latest_valid_hash of an invalid payload.
let (_latest_valid_hash, payload_verification_status) =
if is_execution_enabled(&state, block.message().body()) {
let execution_layer = chain
.execution_layer
@@ -1159,15 +1161,15 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
.block_on(|execution_layer| execution_layer.execute_payload(execution_payload));
match execute_payload_response {
Ok((status, handle)) => match status {
ExecutePayloadResponse::Valid => {
(handle, PayloadVerificationStatus::Verified)
Ok((status, latest_valid_hash)) => match status {
ExecutePayloadResponseStatus::Valid => {
(latest_valid_hash, PayloadVerificationStatus::Verified)
}
ExecutePayloadResponse::Invalid => {
ExecutePayloadResponseStatus::Invalid => {
return Err(ExecutionPayloadError::RejectedByExecutionEngine.into());
}
ExecutePayloadResponse::Syncing => {
(handle, PayloadVerificationStatus::NotVerified)
ExecutePayloadResponseStatus::Syncing => {
(latest_valid_hash, PayloadVerificationStatus::NotVerified)
}
},
Err(_) => (None, PayloadVerificationStatus::NotVerified),
@@ -1274,15 +1276,6 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
});
}
// If this block required an `executePayload` call to the execution node, inform it that the
// block is indeed valid.
//
// If the handle is dropped without explicitly declaring validity, an invalid message will
// be sent to the execution engine.
if let Some(execute_payload_handle) = execute_payload_handle {
execute_payload_handle.publish_consensus_valid();
}
Ok(Self {
block,
block_root,

View File

@@ -183,6 +183,8 @@ pub enum BlockProductionError {
ExecutionLayerMissing,
TerminalPoWBlockLookupFailed(execution_layer::Error),
GetPayloadFailed(execution_layer::Error),
FailedToReadFinalizedBlock(store::Error),
MissingFinalizedBlock(Hash256),
}
easy_from_to!(BlockProcessingError, BlockProductionError);