Skip to content

Commit 866b80f

Browse files
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 <[email protected]>
1 parent 10e28d9 commit 866b80f

File tree

17 files changed

+1268
-912
lines changed

17 files changed

+1268
-912
lines changed

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2908,10 +2908,30 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
29082908
let timestamp =
29092909
compute_timestamp_at_slot(&state, &self.spec).map_err(BeaconStateError::from)?;
29102910
let random = *state.get_randao_mix(state.current_epoch())?;
2911+
let finalized_root = state.finalized_checkpoint().root;
2912+
2913+
let finalized_block_hash =
2914+
if let Some(block) = self.fork_choice.read().get_block(&finalized_root) {
2915+
block.execution_status.block_hash()
2916+
} else {
2917+
self.store
2918+
.get_block(&finalized_root)
2919+
.map_err(BlockProductionError::FailedToReadFinalizedBlock)?
2920+
.ok_or(BlockProductionError::MissingFinalizedBlock(finalized_root))?
2921+
.message()
2922+
.body()
2923+
.execution_payload()
2924+
.map(|ep| ep.block_hash)
2925+
};
29112926

29122927
execution_layer
29132928
.block_on(|execution_layer| {
2914-
execution_layer.get_payload(parent_hash, timestamp, random)
2929+
execution_layer.get_payload(
2930+
parent_hash,
2931+
timestamp,
2932+
random,
2933+
finalized_block_hash.unwrap_or_else(Hash256::zero),
2934+
)
29152935
})
29162936
.map_err(BlockProductionError::GetPayloadFailed)
29172937
};
@@ -3168,7 +3188,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
31683188
.attester_shuffling_decision_root(self.genesis_block_root, RelativeEpoch::Current);
31693189

31703190
// Used later for the execution engine.
3171-
let new_head_execution_block_hash = new_head
3191+
let new_head_execution_block_hash_opt = new_head
31723192
.beacon_block
31733193
.message()
31743194
.body()
@@ -3404,7 +3424,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
34043424
}
34053425

34063426
// If this is a post-merge block, update the execution layer.
3407-
if let Some(block_hash) = new_head_execution_block_hash {
3427+
if let Some(new_head_execution_block_hash) = new_head_execution_block_hash_opt {
34083428
if is_merge_complete {
34093429
let execution_layer = self
34103430
.execution_layer
@@ -3420,7 +3440,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
34203440
execution_layer,
34213441
store,
34223442
new_finalized_checkpoint.root,
3423-
block_hash,
3443+
new_head_execution_block_hash,
34243444
)
34253445
.await
34263446
{
@@ -3461,7 +3481,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
34613481
.unwrap_or_else(Hash256::zero);
34623482

34633483
execution_layer
3464-
.forkchoice_updated(head_execution_block_hash, finalized_execution_block_hash)
3484+
.notify_forkchoice_updated(
3485+
head_execution_block_hash,
3486+
finalized_execution_block_hash,
3487+
None,
3488+
)
34653489
.await
34663490
.map_err(Error::ExecutionForkChoiceUpdateFailed)
34673491
}

beacon_node/beacon_chain/src/block_verification.rs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use crate::{
5050
},
5151
metrics, BeaconChain, BeaconChainError, BeaconChainTypes,
5252
};
53-
use execution_layer::ExecutePayloadResponse;
53+
use execution_layer::ExecutePayloadResponseStatus;
5454
use fork_choice::{ForkChoice, ForkChoiceStore, PayloadVerificationStatus};
5555
use parking_lot::RwLockReadGuard;
5656
use proto_array::{Block as ProtoBlock, ExecutionStatus};
@@ -1139,7 +1139,9 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
11391139
}
11401140

11411141
// This is the soonest we can run these checks as they must be called AFTER per_slot_processing
1142-
let (execute_payload_handle, payload_verification_status) =
1142+
//
1143+
// TODO(merge): handle the latest_valid_hash of an invalid payload.
1144+
let (_latest_valid_hash, payload_verification_status) =
11431145
if is_execution_enabled(&state, block.message().body()) {
11441146
let execution_layer = chain
11451147
.execution_layer
@@ -1159,15 +1161,15 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
11591161
.block_on(|execution_layer| execution_layer.execute_payload(execution_payload));
11601162

11611163
match execute_payload_response {
1162-
Ok((status, handle)) => match status {
1163-
ExecutePayloadResponse::Valid => {
1164-
(handle, PayloadVerificationStatus::Verified)
1164+
Ok((status, latest_valid_hash)) => match status {
1165+
ExecutePayloadResponseStatus::Valid => {
1166+
(latest_valid_hash, PayloadVerificationStatus::Verified)
11651167
}
1166-
ExecutePayloadResponse::Invalid => {
1168+
ExecutePayloadResponseStatus::Invalid => {
11671169
return Err(ExecutionPayloadError::RejectedByExecutionEngine.into());
11681170
}
1169-
ExecutePayloadResponse::Syncing => {
1170-
(handle, PayloadVerificationStatus::NotVerified)
1171+
ExecutePayloadResponseStatus::Syncing => {
1172+
(latest_valid_hash, PayloadVerificationStatus::NotVerified)
11711173
}
11721174
},
11731175
Err(_) => (None, PayloadVerificationStatus::NotVerified),
@@ -1274,15 +1276,6 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
12741276
});
12751277
}
12761278

1277-
// If this block required an `executePayload` call to the execution node, inform it that the
1278-
// block is indeed valid.
1279-
//
1280-
// If the handle is dropped without explicitly declaring validity, an invalid message will
1281-
// be sent to the execution engine.
1282-
if let Some(execute_payload_handle) = execute_payload_handle {
1283-
execute_payload_handle.publish_consensus_valid();
1284-
}
1285-
12861279
Ok(Self {
12871280
block,
12881281
block_root,

beacon_node/beacon_chain/src/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ pub enum BlockProductionError {
183183
ExecutionLayerMissing,
184184
TerminalPoWBlockLookupFailed(execution_layer::Error),
185185
GetPayloadFailed(execution_layer::Error),
186+
FailedToReadFinalizedBlock(store::Error),
187+
MissingFinalizedBlock(Hash256),
186188
}
187189

188190
easy_from_to!(BlockProcessingError, BlockProductionError);

beacon_node/execution_layer/src/engine_api.rs

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ use serde::{Deserialize, Serialize};
44

55
pub const LATEST_TAG: &str = "latest";
66

7+
use crate::engines::ForkChoiceState;
78
pub use types::{Address, EthSpec, ExecutionPayload, Hash256, Uint256};
89

910
pub mod http;
11+
pub mod json_structures;
1012

11-
pub type PayloadId = u64;
13+
pub type PayloadId = [u8; 8];
1214

1315
#[derive(Debug)]
1416
pub enum Error {
@@ -23,6 +25,7 @@ pub enum Error {
2325
ExecutionBlockNotFound(Hash256),
2426
ExecutionHeadBlockNotFound,
2527
ParentHashEqualsBlockHash(Hash256),
28+
PayloadIdUnavailable,
2629
}
2730

2831
impl From<reqwest::Error> for Error {
@@ -52,50 +55,35 @@ pub trait EngineApi {
5255
block_hash: Hash256,
5356
) -> Result<Option<ExecutionBlock>, Error>;
5457

55-
async fn prepare_payload(
56-
&self,
57-
parent_hash: Hash256,
58-
timestamp: u64,
59-
random: Hash256,
60-
fee_recipient: Address,
61-
) -> Result<PayloadId, Error>;
62-
63-
async fn execute_payload<T: EthSpec>(
58+
async fn execute_payload_v1<T: EthSpec>(
6459
&self,
6560
execution_payload: ExecutionPayload<T>,
6661
) -> Result<ExecutePayloadResponse, Error>;
6762

68-
async fn get_payload<T: EthSpec>(
63+
async fn get_payload_v1<T: EthSpec>(
6964
&self,
7065
payload_id: PayloadId,
7166
) -> Result<ExecutionPayload<T>, Error>;
7267

73-
async fn consensus_validated(
74-
&self,
75-
block_hash: Hash256,
76-
status: ConsensusStatus,
77-
) -> Result<(), Error>;
78-
79-
async fn forkchoice_updated(
68+
async fn forkchoice_updated_v1(
8069
&self,
81-
head_block_hash: Hash256,
82-
finalized_block_hash: Hash256,
83-
) -> Result<(), Error>;
70+
forkchoice_state: ForkChoiceState,
71+
payload_attributes: Option<PayloadAttributes>,
72+
) -> Result<ForkchoiceUpdatedResponse, Error>;
8473
}
8574

86-
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
87-
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
88-
pub enum ExecutePayloadResponse {
75+
#[derive(Clone, Copy, Debug, PartialEq)]
76+
pub enum ExecutePayloadResponseStatus {
8977
Valid,
9078
Invalid,
9179
Syncing,
9280
}
9381

94-
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
95-
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
96-
pub enum ConsensusStatus {
97-
Valid,
98-
Invalid,
82+
#[derive(Clone, Debug, PartialEq)]
83+
pub struct ExecutePayloadResponse {
84+
pub status: ExecutePayloadResponseStatus,
85+
pub latest_valid_hash: Option<Hash256>,
86+
pub message: Option<String>,
9987
}
10088

10189
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
@@ -114,3 +102,21 @@ pub struct ExecutionBlock {
114102
pub parent_hash: Hash256,
115103
pub total_difficulty: Uint256,
116104
}
105+
106+
#[derive(Clone, Copy, Debug)]
107+
pub struct PayloadAttributes {
108+
pub timestamp: u64,
109+
pub random: Hash256,
110+
pub fee_recipient: Address,
111+
}
112+
113+
#[derive(Clone, Copy, Debug, PartialEq)]
114+
pub enum ForkchoiceUpdatedResponseStatus {
115+
Success,
116+
Syncing,
117+
}
118+
#[derive(Clone, Debug, PartialEq)]
119+
pub struct ForkchoiceUpdatedResponse {
120+
pub status: ForkchoiceUpdatedResponseStatus,
121+
pub payload_id: Option<PayloadId>,
122+
}

0 commit comments

Comments
 (0)