Engine API v1.0.0.alpha.6 + interop tests (#3024)

## Issue Addressed

NA

## Proposed Changes

This PR extends #3018 to address my review comments there and add automated integration tests with Geth (and other implementations, in the future).

I've also de-duplicated the "unused port" logic by creating an  `common/unused_port` crate.

## Additional Info

I'm not sure if we want to merge this PR, or update #3018 and merge that. I don't mind, I'm primarily opening this PR to make sure CI works.


Co-authored-by: Mark Mackey <mark@sigmaprime.io>
This commit is contained in:
Paul Hauner
2022-02-17 21:47:06 +00:00
parent 2f8531dc60
commit 0a6a8ea3b0
40 changed files with 1125 additions and 363 deletions

View File

@@ -1,6 +1,5 @@
use crate::engine_api::{
ExecutePayloadResponse, ExecutePayloadResponseStatus, ExecutionBlock, PayloadAttributes,
PayloadId,
ExecutionBlock, PayloadAttributes, PayloadId, PayloadStatusV1, PayloadStatusV1Status,
};
use crate::engines::ForkChoiceState;
use serde::{Deserialize, Serialize};
@@ -235,20 +234,20 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
self.payload_ids.remove(id)
}
pub fn notify_new_payload(&mut self, payload: ExecutionPayload<T>) -> ExecutePayloadResponse {
pub fn new_payload(&mut self, payload: ExecutionPayload<T>) -> PayloadStatusV1 {
let parent = if let Some(parent) = self.blocks.get(&payload.parent_hash) {
parent
} else {
return ExecutePayloadResponse {
status: ExecutePayloadResponseStatus::Syncing,
return PayloadStatusV1 {
status: PayloadStatusV1Status::Syncing,
latest_valid_hash: None,
validation_error: None,
};
};
if payload.block_number != parent.block_number() + 1 {
return ExecutePayloadResponse {
status: ExecutePayloadResponseStatus::Invalid,
return PayloadStatusV1 {
status: PayloadStatusV1Status::Invalid,
latest_valid_hash: Some(parent.block_hash()),
validation_error: Some("invalid block number".to_string()),
};
@@ -257,8 +256,8 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
let valid_hash = payload.block_hash;
self.pending_payloads.insert(payload.block_hash, payload);
ExecutePayloadResponse {
status: ExecutePayloadResponseStatus::Valid,
PayloadStatusV1 {
status: PayloadStatusV1Status::Valid,
latest_valid_hash: Some(valid_hash),
validation_error: None,
}

View File

@@ -1,5 +1,5 @@
use super::Context;
use crate::engine_api::{http::*, ExecutePayloadResponse, ExecutePayloadResponseStatus};
use crate::engine_api::{http::*, PayloadStatusV1, PayloadStatusV1Status};
use crate::json_structures::*;
use serde::de::DeserializeOwned;
use serde_json::Value as JsonValue;
@@ -54,30 +54,30 @@ pub async fn handle_rpc<T: EthSpec>(
)
.unwrap())
}
ENGINE_EXECUTE_PAYLOAD_V1 => {
ENGINE_NEW_PAYLOAD_V1 => {
let request: JsonExecutionPayloadV1<T> = get_param(params, 0)?;
let response = if let Some(status) = *ctx.static_notify_new_payload_response.lock() {
let response = if let Some(status) = *ctx.static_new_payload_response.lock() {
match status {
ExecutePayloadResponseStatus::Valid => ExecutePayloadResponse {
PayloadStatusV1Status::Valid => PayloadStatusV1 {
status,
latest_valid_hash: Some(request.block_hash),
validation_error: None,
},
ExecutePayloadResponseStatus::Syncing => ExecutePayloadResponse {
PayloadStatusV1Status::Syncing => PayloadStatusV1 {
status,
latest_valid_hash: None,
validation_error: None,
},
_ => unimplemented!("invalid static executePayloadResponse"),
_ => unimplemented!("invalid static newPayloadResponse"),
}
} else {
ctx.execution_block_generator
.write()
.notify_new_payload(request.into())
.new_payload(request.into())
};
Ok(serde_json::to_value(JsonExecutePayloadV1Response::from(response)).unwrap())
Ok(serde_json::to_value(JsonPayloadStatusV1::from(response)).unwrap())
}
ENGINE_GET_PAYLOAD_V1 => {
let request: JsonPayloadIdRequest = get_param(params, 0)?;
@@ -94,6 +94,8 @@ pub async fn handle_rpc<T: EthSpec>(
ENGINE_FORKCHOICE_UPDATED_V1 => {
let forkchoice_state: JsonForkChoiceStateV1 = get_param(params, 0)?;
let payload_attributes: Option<JsonPayloadAttributesV1> = get_param(params, 1)?;
let head_block_hash = forkchoice_state.head_block_hash;
let id = ctx
.execution_block_generator
.write()
@@ -103,7 +105,11 @@ pub async fn handle_rpc<T: EthSpec>(
)?;
Ok(serde_json::to_value(JsonForkchoiceUpdatedV1Response {
status: JsonForkchoiceUpdatedV1ResponseStatus::Success,
payload_status: JsonPayloadStatusV1 {
status: JsonPayloadStatusV1Status::Valid,
latest_valid_hash: Some(head_block_hash),
validation_error: None,
},
payload_id: id.map(Into::into),
})
.unwrap())

View File

@@ -147,8 +147,8 @@ impl<T: EthSpec> MockExecutionLayer<T> {
let (payload_response, latest_valid_hash) =
self.el.notify_new_payload(&payload).await.unwrap();
assert_eq!(payload_response, ExecutePayloadResponseStatus::Valid);
assert_eq!(latest_valid_hash, Some(payload.block_hash));
assert_eq!(payload_response, PayloadStatusV1Status::Valid);
assert_eq!(latest_valid_hash, Some(vec![payload.block_hash]));
self.el
.notify_forkchoice_updated(block_hash, Hash256::zero(), None)

View File

@@ -1,7 +1,7 @@
//! Provides a mock execution engine HTTP JSON-RPC API for use in testing.
use crate::engine_api::http::JSONRPC_VERSION;
use crate::engine_api::ExecutePayloadResponseStatus;
use crate::engine_api::PayloadStatusV1Status;
use bytes::Bytes;
use environment::null_logger;
use execution_block_generator::{Block, PoWBlock};
@@ -62,7 +62,7 @@ impl<T: EthSpec> MockServer<T> {
last_echo_request: last_echo_request.clone(),
execution_block_generator: RwLock::new(execution_block_generator),
preloaded_responses,
static_notify_new_payload_response: <_>::default(),
static_new_payload_response: <_>::default(),
_phantom: PhantomData,
});
@@ -117,8 +117,7 @@ impl<T: EthSpec> MockServer<T> {
}
pub fn all_payloads_valid(&self) {
*self.ctx.static_notify_new_payload_response.lock() =
Some(ExecutePayloadResponseStatus::Valid)
*self.ctx.static_new_payload_response.lock() = Some(PayloadStatusV1Status::Valid)
}
pub fn insert_pow_block(
@@ -188,7 +187,7 @@ pub struct Context<T: EthSpec> {
pub last_echo_request: Arc<RwLock<Option<Bytes>>>,
pub execution_block_generator: RwLock<ExecutionBlockGenerator<T>>,
pub preloaded_responses: Arc<Mutex<Vec<serde_json::Value>>>,
pub static_notify_new_payload_response: Arc<Mutex<Option<ExecutePayloadResponseStatus>>>,
pub static_new_payload_response: Arc<Mutex<Option<PayloadStatusV1Status>>>,
pub _phantom: PhantomData<T>,
}