diff --git a/Cargo.lock b/Cargo.lock index 7879299665..44f64a0c1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3468,7 +3468,10 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine", + "async-trait", "derive_more 2.0.1", + "eyre", + "jsonrpsee", "op-alloy-consensus", "op-alloy-rpc-types-engine", "reth-chain-state", @@ -3482,6 +3485,7 @@ dependencies = [ "reth-optimism-node", "reth-optimism-primitives", "reth-primitives-traits", + "reth-rpc-api", "revm-primitives", "serde", ] diff --git a/examples/custom-node/Cargo.toml b/examples/custom-node/Cargo.toml index dc4d2b0511..e9d60908d3 100644 --- a/examples/custom-node/Cargo.toml +++ b/examples/custom-node/Cargo.toml @@ -18,6 +18,7 @@ reth-optimism-forks.workspace = true reth-optimism-node.workspace = true reth-optimism-primitives = { workspace = true, features = ["serde", "reth-codec"] } reth-primitives-traits.workspace = true +reth-rpc-api.workspace = true # revm revm-primitives.workspace = true @@ -33,8 +34,11 @@ op-alloy-consensus.workspace = true op-alloy-rpc-types-engine.workspace = true # misc +async-trait.workspace = true derive_more.workspace = true +eyre.workspace = true serde.workspace = true +jsonrpsee.workspace = true [features] default = [] diff --git a/examples/custom-node/src/engine.rs b/examples/custom-node/src/engine.rs index 5c513bc56a..9d829abd0e 100644 --- a/examples/custom-node/src/engine.rs +++ b/examples/custom-node/src/engine.rs @@ -1,25 +1,18 @@ use crate::primitives::CustomNodePrimitives; -use alloy_rpc_types_engine::{ - BlobsBundleV1, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, -}; -use op_alloy_rpc_types_engine::{ - OpExecutionData, OpExecutionPayload, OpExecutionPayloadEnvelopeV3, - OpExecutionPayloadEnvelopeV4, OpExecutionPayloadV4, -}; +use op_alloy_rpc_types_engine::{OpExecutionData, OpExecutionPayload}; use reth_chain_state::ExecutedBlockWithTrieUpdates; use reth_node_api::{ - BuiltPayload, EngineTypes, ExecutionPayload, NodePrimitives, PayloadAttributes, - PayloadBuilderAttributes, PayloadTypes, + BuiltPayload, ExecutionPayload, NodePrimitives, PayloadAttributes, PayloadBuilderAttributes, + PayloadTypes, }; use reth_optimism_node::{OpBuiltPayload, OpPayloadAttributes, OpPayloadBuilderAttributes}; use reth_optimism_primitives::OpTransactionSigned; use reth_primitives_traits::SealedBlock; use revm_primitives::U256; use serde::{Deserialize, Serialize}; -use std::sync::Arc; #[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct CustomEngineTypes; +pub struct CustomPayloadTypes; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CustomExecutionData { @@ -164,79 +157,7 @@ impl From } } -impl From for ExecutionPayloadV1 { - fn from(value: CustomBuiltPayload) -> Self { - Self::from_block_unchecked(value.block().hash(), &value.into()) - } -} - -impl From for ExecutionPayloadV2 { - fn from(value: CustomBuiltPayload) -> Self { - Self::from_block_unchecked(value.block().hash(), &value.into()) - } -} - -impl From for OpExecutionPayloadEnvelopeV3 { - fn from(value: CustomBuiltPayload) -> Self { - Self { - block_value: value.fees(), - // From the engine API spec: - // - // > Client software **MAY** use any heuristics to decide whether to set - // `shouldOverrideBuilder` flag or not. If client software does not implement any - // heuristic this flag **SHOULD** be set to `false`. - // - // Spec: - // - should_override_builder: false, - // No blobs for OP. - blobs_bundle: BlobsBundleV1 { blobs: vec![], commitments: vec![], proofs: vec![] }, - parent_beacon_block_root: value.0.block().parent_beacon_block_root.unwrap_or_default(), - execution_payload: ExecutionPayloadV3::from_block_unchecked( - value.0.block().hash(), - &value.into(), - ), - } - } -} - -impl From for OpExecutionPayloadEnvelopeV4 { - fn from(value: CustomBuiltPayload) -> Self { - let fees = value.0.fees(); - let block = value.0.into_sealed_block(); - - let parent_beacon_block_root = block.parent_beacon_block_root.unwrap_or_default(); - - let l2_withdrawals_root = block.withdrawals_root.unwrap_or_default(); - let payload_v3 = ExecutionPayloadV3::from_block_unchecked( - block.hash(), - &Arc::unwrap_or_clone(block.into()).into_block(), - ); - - Self { - execution_payload: OpExecutionPayloadV4::from_v3_with_withdrawals_root( - payload_v3, - l2_withdrawals_root, - ), - block_value: fees, - // From the engine API spec: - // - // > Client software **MAY** use any heuristics to decide whether to set - // `shouldOverrideBuilder` flag or not. If client software does not implement any - // heuristic this flag **SHOULD** be set to `false`. - // - // Spec: - // - should_override_builder: false, - // No blobs for OP. - blobs_bundle: BlobsBundleV1 { blobs: vec![], commitments: vec![], proofs: vec![] }, - parent_beacon_block_root, - execution_requests: vec![], - } - } -} - -impl PayloadTypes for CustomEngineTypes { +impl PayloadTypes for CustomPayloadTypes { type BuiltPayload = CustomBuiltPayload; type PayloadAttributes = CustomPayloadAttributes; type PayloadBuilderAttributes = CustomPayloadBuilderAttributes; @@ -254,10 +175,3 @@ impl PayloadTypes for CustomEngineTypes { CustomExecutionData { inner: OpExecutionData { payload, sidecar }, extension } } } - -impl EngineTypes for CustomEngineTypes { - type ExecutionPayloadEnvelopeV1 = ExecutionPayloadV1; - type ExecutionPayloadEnvelopeV2 = ExecutionPayloadV2; - type ExecutionPayloadEnvelopeV3 = OpExecutionPayloadEnvelopeV3; - type ExecutionPayloadEnvelopeV4 = OpExecutionPayloadEnvelopeV4; -} diff --git a/examples/custom-node/src/engine_api.rs b/examples/custom-node/src/engine_api.rs new file mode 100644 index 0000000000..3e94c89210 --- /dev/null +++ b/examples/custom-node/src/engine_api.rs @@ -0,0 +1,94 @@ +use crate::{ + chainspec::CustomChainSpec, + engine::{CustomPayloadAttributes, CustomPayloadTypes}, + primitives::CustomNodePrimitives, +}; +use alloy_rpc_types_engine::{ + ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, PayloadStatusEnum, +}; +use async_trait::async_trait; +use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule}; +use reth_node_api::{AddOnsContext, FullNodeComponents, NodeTypes}; +use reth_node_builder::rpc::EngineApiBuilder; +use reth_optimism_node::node::OpStorage; +use reth_rpc_api::IntoEngineApiRpcModule; + +#[derive(serde::Deserialize)] +pub struct CustomExecutionPayloadInput {} + +#[derive(Clone, serde::Serialize)] +pub struct CustomExecutionPayloadEnvelope {} + +#[rpc(server, namespace = "engine")] +pub trait CustomEngineApi { + #[method(name = "newPayload")] + async fn new_payload(&self, payload: CustomExecutionPayloadInput) -> RpcResult; + + #[method(name = "forkchoiceUpdated")] + async fn fork_choice_updated( + &self, + fork_choice_state: ForkchoiceState, + payload_attributes: Option, + ) -> RpcResult; + + #[method(name = "getPayload")] + async fn get_payload(&self, payload_id: PayloadId) + -> RpcResult; +} + +pub struct CustomEngineApi {} + +#[async_trait] +impl CustomEngineApiServer for CustomEngineApi { + async fn new_payload(&self, _payload: CustomExecutionPayloadInput) -> RpcResult { + Ok(PayloadStatus::from_status(PayloadStatusEnum::Valid)) + } + + async fn fork_choice_updated( + &self, + _fork_choice_state: ForkchoiceState, + _payload_attributes: Option, + ) -> RpcResult { + Ok(ForkchoiceUpdated { + payload_status: PayloadStatus::from_status(PayloadStatusEnum::Valid), + payload_id: Some(PayloadId::default()), + }) + } + + async fn get_payload( + &self, + _payload_id: PayloadId, + ) -> RpcResult { + Ok(CustomExecutionPayloadEnvelope {}) + } +} + +impl IntoEngineApiRpcModule for CustomEngineApi +where + Self: CustomEngineApiServer, +{ + fn into_rpc_module(self) -> RpcModule<()> { + self.into_rpc().remove_context() + } +} + +#[derive(Debug, Default)] +pub struct CustomEngineApiBuilder {} + +impl EngineApiBuilder for CustomEngineApiBuilder +where + N: FullNodeComponents< + Types: NodeTypes< + Payload = CustomPayloadTypes, + ChainSpec = CustomChainSpec, + Primitives = CustomNodePrimitives, + Storage = OpStorage, + >, + >, +{ + type EngineApi = CustomEngineApi; + + async fn build_engine_api(self, _ctx: &AddOnsContext<'_, N>) -> eyre::Result { + Ok(CustomEngineApi {}) + } +} diff --git a/examples/custom-node/src/lib.rs b/examples/custom-node/src/lib.rs index 676b816177..d84c708e3e 100644 --- a/examples/custom-node/src/lib.rs +++ b/examples/custom-node/src/lib.rs @@ -8,7 +8,7 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] use chainspec::CustomChainSpec; -use engine::CustomEngineTypes; +use engine::CustomPayloadTypes; use primitives::CustomNodePrimitives; use reth_node_api::{FullNodeTypes, NodeTypes}; use reth_node_builder::{components::ComponentsBuilder, Node, NodeComponentsBuilder}; @@ -19,6 +19,7 @@ use reth_optimism_node::{ pub mod chainspec; pub mod engine; +pub mod engine_api; pub mod primitives; #[derive(Debug, Clone)] @@ -29,14 +30,14 @@ impl NodeTypes for CustomNode { type ChainSpec = CustomChainSpec; type StateCommitment = ::StateCommitment; type Storage = ::Storage; - type Payload = CustomEngineTypes; + type Payload = CustomPayloadTypes; } impl Node for CustomNode where N: FullNodeTypes< Types: NodeTypes< - Payload = CustomEngineTypes, + Payload = CustomPayloadTypes, ChainSpec = CustomChainSpec, Primitives = CustomNodePrimitives, Storage = OpStorage,