diff --git a/crates/rpc/rpc-api/src/engine.rs b/crates/rpc/rpc-api/src/engine.rs index 6d22fc89f9e..2c8075ebab6 100644 --- a/crates/rpc/rpc-api/src/engine.rs +++ b/crates/rpc/rpc-api/src/engine.rs @@ -3,7 +3,7 @@ use reth_primitives::{Address, BlockHash, BlockId, BlockNumberOrTag, Bytes, H256 use reth_rpc_types::{ engine::{ ExecutionPayloadBodiesV1, ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, - ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, ForkchoiceState, + ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, ForkchoiceState, ForkchoiceUpdated, PayloadAttributes, PayloadId, PayloadStatus, TransitionConfiguration, }, state::StateOverride, @@ -18,9 +18,9 @@ pub trait EngineApi { #[method(name = "newPayloadV1")] async fn new_payload_v1(&self, payload: ExecutionPayloadV1) -> RpcResult; - /// See also + /// See also #[method(name = "newPayloadV2")] - async fn new_payload_v2(&self, payload: ExecutionPayloadV2) -> RpcResult; + async fn new_payload_v2(&self, payload: ExecutionPayloadInputV2) -> RpcResult; /// Post Cancun payload handler /// diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index b7aa7c6a688..8f05f5d4aab 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -11,7 +11,7 @@ use reth_provider::{BlockReader, EvmEnvProvider, HeaderProvider, StateProviderFa use reth_rpc_api::EngineApiServer; use reth_rpc_types::engine::{ CancunPayloadFields, ExecutionPayload, ExecutionPayloadBodiesV1, ExecutionPayloadEnvelopeV2, - ExecutionPayloadEnvelopeV3, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, + ExecutionPayloadEnvelopeV3, ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, ForkchoiceUpdated, PayloadAttributes, PayloadId, PayloadStatus, TransitionConfiguration, CAPABILITIES, }; @@ -79,10 +79,10 @@ where Ok(self.inner.beacon_consensus.new_payload(payload, None).await?) } - /// See also + /// See also pub async fn new_payload_v2( &self, - payload: ExecutionPayloadV2, + payload: ExecutionPayloadInputV2, ) -> EngineApiResult { let payload = ExecutionPayload::from(payload); let payload_or_attrs = PayloadOrAttributes::from_execution_payload(&payload, None); @@ -592,8 +592,8 @@ where } /// Handler for `engine_newPayloadV2` - /// See also - async fn new_payload_v2(&self, payload: ExecutionPayloadV2) -> RpcResult { + /// See also + async fn new_payload_v2(&self, payload: ExecutionPayloadInputV2) -> RpcResult { trace!(target: "rpc::engine", "Serving engine_newPayloadV2"); Ok(EngineApi::new_payload_v2(self, payload).await?) } diff --git a/crates/rpc/rpc-types/src/eth/engine/payload.rs b/crates/rpc/rpc-types/src/eth/engine/payload.rs index 6b53c4e84cd..9b6dcea0720 100644 --- a/crates/rpc/rpc-types/src/eth/engine/payload.rs +++ b/crates/rpc/rpc-types/src/eth/engine/payload.rs @@ -71,6 +71,48 @@ impl From for ExecutionPayloadFieldV2 { } } +impl From for ExecutionPayload { + fn from(value: ExecutionPayloadFieldV2) -> Self { + match value { + ExecutionPayloadFieldV2::V1(payload) => ExecutionPayload::V1(payload), + ExecutionPayloadFieldV2::V2(payload) => ExecutionPayload::V2(payload), + } + } +} + +/// This is the input to `engine_newPayloadV2`, which may or may not have a withdrawals field. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ExecutionPayloadInputV2 { + /// The V1 execution payload + #[serde(flatten)] + pub execution_payload: ExecutionPayloadV1, + /// The payload withdrawals + #[serde(default, skip_serializing_if = "Option::is_none")] + pub withdrawals: Option>, +} + +impl From for ExecutionPayload { + fn from(value: ExecutionPayloadInputV2) -> Self { + match value.withdrawals { + Some(withdrawals) => ExecutionPayload::V2(ExecutionPayloadV2 { + payload_inner: value.execution_payload, + withdrawals, + }), + None => ExecutionPayload::V1(value.execution_payload), + } + } +} + +impl From for ExecutionPayloadInputV2 { + fn from(value: SealedBlock) -> Self { + ExecutionPayloadInputV2 { + withdrawals: value.withdrawals.clone(), + execution_payload: value.into(), + } + } +} + /// This structure maps for the return value of `engine_getPayload` of the beacon chain spec, for /// V2. /// @@ -898,4 +940,64 @@ mod tests { let envelope: ExecutionPayloadEnvelopeV3 = serde_json::from_str(response).unwrap(); assert_eq!(serde_json::to_string(&envelope).unwrap(), response); } + + #[test] + fn serde_deserialize_execution_payload_input_v2() { + let response = r#" +{ + "baseFeePerGas": "0x173b30b3", + "blockHash": "0x99d486755fd046ad0bbb60457bac93d4856aa42fa00629cc7e4a28b65b5f8164", + "blockNumber": "0xb", + "extraData": "0xd883010d01846765746888676f312e32302e33856c696e7578", + "feeRecipient": "0x0000000000000000000000000000000000000000", + "gasLimit": "0x405829", + "gasUsed": "0x3f0ca0", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "parentHash": "0xfe34aaa2b869c66a727783ee5ad3e3983b6ef22baf24a1e502add94e7bcac67a", + "prevRandao": "0x74132c32fe3ab9a470a8352544514d21b6969e7749f97742b53c18a1b22b396c", + "receiptsRoot": "0x6a5c41dc55a1bd3e74e7f6accc799efb08b00c36c15265058433fcea6323e95f", + "stateRoot": "0xde3b357f5f099e4c33d0343c9e9d204d663d7bd9c65020a38e5d0b2a9ace78a2", + "timestamp": "0x6507d6b4", + "transactions": [ + "0xf86d0a8458b20efd825208946177843db3138ae69679a54b95cf345ed759450d8806f3e8d87878800080820a95a0f8bddb1dcc4558b532ff747760a6f547dd275afdbe7bdecc90680e71de105757a014f34ba38c180913c0543b0ac2eccfb77cc3f801a535008dc50e533fbe435f53", + "0xf86d0b8458b20efd82520894687704db07e902e9a8b3754031d168d46e3d586e8806f3e8d87878800080820a95a0e3108f710902be662d5c978af16109961ffaf2ac4f88522407d40949a9574276a0205719ed21889b42ab5c1026d40b759a507c12d92db0d100fa69e1ac79137caa", + "0xf86d0c8458b20efd8252089415e6a5a2e131dd5467fa1ff3acd104f45ee5940b8806f3e8d87878800080820a96a0af556ba9cda1d686239e08c24e169dece7afa7b85e0948eaa8d457c0561277fca029da03d3af0978322e54ac7e8e654da23934e0dd839804cb0430f8aaafd732dc", + "0xf8521784565adcb7830186a0808080820a96a0ec782872a673a9fe4eff028a5bdb30d6b8b7711f58a187bf55d3aec9757cb18ea001796d373da76f2b0aeda72183cce0ad070a4f03aa3e6fee4c757a9444245206", + "0xf8521284565adcb7830186a0808080820a95a08a0ea89028eff02596b385a10e0bd6ae098f3b281be2c95a9feb1685065d7384a06239d48a72e4be767bd12f317dd54202f5623a33e71e25a87cb25dd781aa2fc8", + "0xf8521384565adcb7830186a0808080820a95a0784dbd311a82f822184a46f1677a428cbe3a2b88a798fb8ad1370cdbc06429e8a07a7f6a0efd428e3d822d1de9a050b8a883938b632185c254944dd3e40180eb79" + ], + "withdrawals": [] +} + "#; + let payload: ExecutionPayloadInputV2 = serde_json::from_str(response).unwrap(); + assert_eq!(payload.withdrawals, Some(vec![])); + + let response = r#" +{ + "baseFeePerGas": "0x173b30b3", + "blockHash": "0x99d486755fd046ad0bbb60457bac93d4856aa42fa00629cc7e4a28b65b5f8164", + "blockNumber": "0xb", + "extraData": "0xd883010d01846765746888676f312e32302e33856c696e7578", + "feeRecipient": "0x0000000000000000000000000000000000000000", + "gasLimit": "0x405829", + "gasUsed": "0x3f0ca0", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "parentHash": "0xfe34aaa2b869c66a727783ee5ad3e3983b6ef22baf24a1e502add94e7bcac67a", + "prevRandao": "0x74132c32fe3ab9a470a8352544514d21b6969e7749f97742b53c18a1b22b396c", + "receiptsRoot": "0x6a5c41dc55a1bd3e74e7f6accc799efb08b00c36c15265058433fcea6323e95f", + "stateRoot": "0xde3b357f5f099e4c33d0343c9e9d204d663d7bd9c65020a38e5d0b2a9ace78a2", + "timestamp": "0x6507d6b4", + "transactions": [ + "0xf86d0a8458b20efd825208946177843db3138ae69679a54b95cf345ed759450d8806f3e8d87878800080820a95a0f8bddb1dcc4558b532ff747760a6f547dd275afdbe7bdecc90680e71de105757a014f34ba38c180913c0543b0ac2eccfb77cc3f801a535008dc50e533fbe435f53", + "0xf86d0b8458b20efd82520894687704db07e902e9a8b3754031d168d46e3d586e8806f3e8d87878800080820a95a0e3108f710902be662d5c978af16109961ffaf2ac4f88522407d40949a9574276a0205719ed21889b42ab5c1026d40b759a507c12d92db0d100fa69e1ac79137caa", + "0xf86d0c8458b20efd8252089415e6a5a2e131dd5467fa1ff3acd104f45ee5940b8806f3e8d87878800080820a96a0af556ba9cda1d686239e08c24e169dece7afa7b85e0948eaa8d457c0561277fca029da03d3af0978322e54ac7e8e654da23934e0dd839804cb0430f8aaafd732dc", + "0xf8521784565adcb7830186a0808080820a96a0ec782872a673a9fe4eff028a5bdb30d6b8b7711f58a187bf55d3aec9757cb18ea001796d373da76f2b0aeda72183cce0ad070a4f03aa3e6fee4c757a9444245206", + "0xf8521284565adcb7830186a0808080820a95a08a0ea89028eff02596b385a10e0bd6ae098f3b281be2c95a9feb1685065d7384a06239d48a72e4be767bd12f317dd54202f5623a33e71e25a87cb25dd781aa2fc8", + "0xf8521384565adcb7830186a0808080820a95a0784dbd311a82f822184a46f1677a428cbe3a2b88a798fb8ad1370cdbc06429e8a07a7f6a0efd428e3d822d1de9a050b8a883938b632185c254944dd3e40180eb79" + ] +} + "#; + let payload: ExecutionPayloadInputV2 = serde_json::from_str(response).unwrap(); + assert_eq!(payload.withdrawals, None); + } }