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

@@ -27,8 +27,8 @@ pub const ETH_GET_BLOCK_BY_HASH_TIMEOUT: Duration = Duration::from_secs(1);
pub const ETH_SYNCING: &str = "eth_syncing";
pub const ETH_SYNCING_TIMEOUT: Duration = Duration::from_millis(250);
pub const ENGINE_EXECUTE_PAYLOAD_V1: &str = "engine_executePayloadV1";
pub const ENGINE_EXECUTE_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(2);
pub const ENGINE_NEW_PAYLOAD_V1: &str = "engine_newPayloadV1";
pub const ENGINE_NEW_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(2);
pub const ENGINE_GET_PAYLOAD_V1: &str = "engine_getPayloadV1";
pub const ENGINE_GET_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(2);
@@ -133,18 +133,14 @@ impl EngineApi for HttpJsonRpc {
.await
}
async fn notify_new_payload_v1<T: EthSpec>(
async fn new_payload_v1<T: EthSpec>(
&self,
execution_payload: ExecutionPayload<T>,
) -> Result<ExecutePayloadResponse, Error> {
) -> Result<PayloadStatusV1, Error> {
let params = json!([JsonExecutionPayloadV1::from(execution_payload)]);
let response: JsonExecutePayloadV1Response = self
.rpc_request(
ENGINE_EXECUTE_PAYLOAD_V1,
params,
ENGINE_EXECUTE_PAYLOAD_TIMEOUT,
)
let response: JsonPayloadStatusV1 = self
.rpc_request(ENGINE_NEW_PAYLOAD_V1, params, ENGINE_NEW_PAYLOAD_TIMEOUT)
.await?;
Ok(response.into())
@@ -486,12 +482,12 @@ mod test {
}
#[tokio::test]
async fn notify_new_payload_v1_request() {
async fn new_payload_v1_request() {
Tester::new()
.assert_request_equals(
|client| async move {
let _ = client
.notify_new_payload_v1::<MainnetEthSpec>(ExecutionPayload {
.new_payload_v1::<MainnetEthSpec>(ExecutionPayload {
parent_hash: Hash256::repeat_byte(0),
fee_recipient: Address::repeat_byte(1),
state_root: Hash256::repeat_byte(1),
@@ -512,7 +508,7 @@ mod test {
json!({
"id": STATIC_ID,
"jsonrpc": JSONRPC_VERSION,
"method": ENGINE_EXECUTE_PAYLOAD_V1,
"method": ENGINE_NEW_PAYLOAD_V1,
"params": [{
"parentHash": HASH_00,
"feeRecipient": ADDRESS_01,
@@ -627,7 +623,11 @@ mod test {
"id": STATIC_ID,
"jsonrpc": JSONRPC_VERSION,
"result": {
"status": "SUCCESS",
"payloadStatus": {
"status": "VALID",
"latestValidHash": HASH_00,
"validationError": ""
},
"payloadId": "0xa247243752eb10b4"
}
})],
@@ -648,7 +648,11 @@ mod test {
.await
.unwrap();
assert_eq!(response, ForkchoiceUpdatedResponse {
status: ForkchoiceUpdatedResponseStatus::Success,
payload_status: PayloadStatusV1 {
status: PayloadStatusV1Status::Valid,
latest_valid_hash: Some(Hash256::zero()),
validation_error: Some(String::new()),
},
payload_id:
Some(str_to_payload_id("0xa247243752eb10b4")),
});
@@ -683,12 +687,12 @@ mod test {
"logsBloom": LOGS_BLOOM_00,
"random": HASH_00,
"blockNumber":"0x1",
"gasLimit":"0x1c9c380",
"gasLimit":"0x1c95111",
"gasUsed":"0x0",
"timestamp":"0x5",
"extraData":"0x",
"baseFeePerGas":"0x7",
"blockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858",
"blockHash":"0x6359b8381a370e2f54072a5784ddd78b6ed024991558c511d4452eb4f6ac898c",
"transactions":[]
}
})],
@@ -706,12 +710,12 @@ mod test {
logs_bloom: vec![0; 256].into(),
random: Hash256::zero(),
block_number: 1,
gas_limit: u64::from_str_radix("1c9c380",16).unwrap(),
gas_limit: u64::from_str_radix("1c95111",16).unwrap(),
gas_used: 0,
timestamp: 5,
extra_data: vec![].into(),
base_fee_per_gas: Uint256::from(7),
block_hash: Hash256::from_str("0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858").unwrap(),
block_hash: Hash256::from_str("0x6359b8381a370e2f54072a5784ddd78b6ed024991558c511d4452eb4f6ac898c").unwrap(),
transactions: vec![].into(),
};
@@ -720,10 +724,10 @@ mod test {
)
.await
.assert_request_equals(
// engine_executePayloadV1 REQUEST validation
// engine_newPayloadV1 REQUEST validation
|client| async move {
let _ = client
.notify_new_payload_v1::<MainnetEthSpec>(ExecutionPayload {
.new_payload_v1::<MainnetEthSpec>(ExecutionPayload {
parent_hash: Hash256::from_str("0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a").unwrap(),
fee_recipient: Address::from_str("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(),
state_root: Hash256::from_str("0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45").unwrap(),
@@ -744,7 +748,7 @@ mod test {
json!({
"id": STATIC_ID,
"jsonrpc": JSONRPC_VERSION,
"method": ENGINE_EXECUTE_PAYLOAD_V1,
"method": ENGINE_NEW_PAYLOAD_V1,
"params": [{
"parentHash":"0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a",
"feeRecipient":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
@@ -765,26 +769,27 @@ mod test {
)
.await
.with_preloaded_responses(
// engine_executePayloadV1 RESPONSE validation
// engine_newPayloadV1 RESPONSE validation
vec![json!({
"jsonrpc": JSONRPC_VERSION,
"id": STATIC_ID,
"result":{
"status":"VALID",
"latestValidHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858"
"latestValidHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858",
"validationError":"",
}
})],
|client| async move {
let response = client
.notify_new_payload_v1::<MainnetEthSpec>(ExecutionPayload::default())
.new_payload_v1::<MainnetEthSpec>(ExecutionPayload::default())
.await
.unwrap();
assert_eq!(response,
ExecutePayloadResponse {
status: ExecutePayloadResponseStatus::Valid,
PayloadStatusV1 {
status: PayloadStatusV1Status::Valid,
latest_valid_hash: Some(Hash256::from_str("0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858").unwrap()),
validation_error: None
validation_error: Some(String::new()),
}
);
},
@@ -819,14 +824,15 @@ mod test {
.await
.with_preloaded_responses(
// engine_forkchoiceUpdatedV1 RESPONSE validation
//
// Note: this test was modified to provide `null` rather than `0x`. The geth vectors
// are invalid.
vec![json!({
"jsonrpc": JSONRPC_VERSION,
"id": STATIC_ID,
"result": {
"status":"SUCCESS",
"payloadStatus": {
"status": "VALID",
"latestValidHash": HASH_00,
"validationError": ""
},
"payloadId": JSON_NULL,
}
})],
@@ -843,7 +849,11 @@ mod test {
.await
.unwrap();
assert_eq!(response, ForkchoiceUpdatedResponse {
status: ForkchoiceUpdatedResponseStatus::Success,
payload_status: PayloadStatusV1 {
status: PayloadStatusV1Status::Valid,
latest_valid_hash: Some(Hash256::zero()),
validation_error: Some(String::new()),
},
payload_id: None,
});
},