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

@@ -1,5 +1,6 @@
use super::Context;
use crate::engine_api::http::*;
use crate::engine_api::{http::*, ExecutePayloadResponse, ExecutePayloadResponseStatus};
use crate::json_structures::*;
use serde::de::DeserializeOwned;
use serde_json::Value as JsonValue;
use std::sync::Arc;
@@ -53,57 +54,59 @@ pub async fn handle_rpc<T: EthSpec>(
)
.unwrap())
}
ENGINE_PREPARE_PAYLOAD => {
let request = get_param_0(params)?;
let payload_id = ctx
.execution_block_generator
.write()
.prepare_payload(request)?;
ENGINE_EXECUTE_PAYLOAD_V1 => {
let request: JsonExecutionPayloadV1<T> = get_param(params, 0)?;
Ok(serde_json::to_value(JsonPayloadIdResponse { payload_id }).unwrap())
let response = if let Some(status) = *ctx.static_execute_payload_response.lock() {
match status {
ExecutePayloadResponseStatus::Valid => ExecutePayloadResponse {
status,
latest_valid_hash: Some(request.block_hash),
message: None,
},
ExecutePayloadResponseStatus::Syncing => ExecutePayloadResponse {
status,
latest_valid_hash: None,
message: None,
},
_ => unimplemented!("invalid static executePayloadResponse"),
}
} else {
ctx.execution_block_generator
.write()
.execute_payload(request.into())
};
Ok(serde_json::to_value(JsonExecutePayloadV1Response::from(response)).unwrap())
}
ENGINE_EXECUTE_PAYLOAD => {
let request: JsonExecutionPayload<T> = get_param_0(params)?;
let status = ctx
.static_execute_payload_response
.lock()
.unwrap_or_else(|| {
ctx.execution_block_generator
.write()
.execute_payload(request.into())
});
Ok(serde_json::to_value(ExecutePayloadResponseWrapper { status }).unwrap())
}
ENGINE_GET_PAYLOAD => {
let request: JsonPayloadIdRequest = get_param_0(params)?;
let id = request.payload_id;
ENGINE_GET_PAYLOAD_V1 => {
let request: JsonPayloadIdRequest = get_param(params, 0)?;
let id = request.into();
let response = ctx
.execution_block_generator
.write()
.get_payload(id)
.ok_or_else(|| format!("no payload for id {}", id))?;
.get_payload(&id)
.ok_or_else(|| format!("no payload for id {:?}", id))?;
Ok(serde_json::to_value(JsonExecutionPayload::from(response)).unwrap())
Ok(serde_json::to_value(JsonExecutionPayloadV1::from(response)).unwrap())
}
ENGINE_CONSENSUS_VALIDATED => {
let request: JsonConsensusValidatedRequest = get_param_0(params)?;
ctx.execution_block_generator
ENGINE_FORKCHOICE_UPDATED_V1 => {
let forkchoice_state: JsonForkChoiceStateV1 = get_param(params, 0)?;
let payload_attributes: Option<JsonPayloadAttributesV1> = get_param(params, 1)?;
let id = ctx
.execution_block_generator
.write()
.consensus_validated(request.block_hash, request.status)?;
.forkchoice_updated_v1(
forkchoice_state.into(),
payload_attributes.map(|json| json.into()),
)?;
Ok(JsonValue::Null)
}
ENGINE_FORKCHOICE_UPDATED => {
let request: JsonForkChoiceUpdatedRequest = get_param_0(params)?;
ctx.execution_block_generator
.write()
.forkchoice_updated(request.head_block_hash, request.finalized_block_hash)?;
Ok(JsonValue::Null)
Ok(serde_json::to_value(JsonForkchoiceUpdatedV1Response {
status: JsonForkchoiceUpdatedV1ResponseStatus::Success,
payload_id: id.map(Into::into),
})
.unwrap())
}
other => Err(format!(
"The method {} does not exist/is not available",
@@ -112,12 +115,12 @@ pub async fn handle_rpc<T: EthSpec>(
}
}
fn get_param_0<T: DeserializeOwned>(params: &JsonValue) -> Result<T, String> {
fn get_param<T: DeserializeOwned>(params: &JsonValue, index: usize) -> Result<T, String> {
params
.get(0)
.ok_or_else(|| "missing/invalid params[0] value".to_string())
.get(index)
.ok_or_else(|| format!("missing/invalid params[{}] value", index))
.and_then(|param| {
serde_json::from_value(param.clone())
.map_err(|e| format!("failed to deserialize param[0]: {:?}", e))
.map_err(|e| format!("failed to deserialize param[{}]: {:?}", index, e))
})
}