mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-11 00:08:13 -05:00
feat(examples): add custom engine API to custom-node example (#15436)
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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<CustomBuiltPayload>
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CustomBuiltPayload> for ExecutionPayloadV1 {
|
||||
fn from(value: CustomBuiltPayload) -> Self {
|
||||
Self::from_block_unchecked(value.block().hash(), &value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CustomBuiltPayload> for ExecutionPayloadV2 {
|
||||
fn from(value: CustomBuiltPayload) -> Self {
|
||||
Self::from_block_unchecked(value.block().hash(), &value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CustomBuiltPayload> 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:
|
||||
// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification-2>
|
||||
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<CustomBuiltPayload> 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:
|
||||
// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification-2>
|
||||
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;
|
||||
}
|
||||
|
||||
94
examples/custom-node/src/engine_api.rs
Normal file
94
examples/custom-node/src/engine_api.rs
Normal file
@@ -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<PayloadStatus>;
|
||||
|
||||
#[method(name = "forkchoiceUpdated")]
|
||||
async fn fork_choice_updated(
|
||||
&self,
|
||||
fork_choice_state: ForkchoiceState,
|
||||
payload_attributes: Option<CustomPayloadAttributes>,
|
||||
) -> RpcResult<ForkchoiceUpdated>;
|
||||
|
||||
#[method(name = "getPayload")]
|
||||
async fn get_payload(&self, payload_id: PayloadId)
|
||||
-> RpcResult<CustomExecutionPayloadEnvelope>;
|
||||
}
|
||||
|
||||
pub struct CustomEngineApi {}
|
||||
|
||||
#[async_trait]
|
||||
impl CustomEngineApiServer for CustomEngineApi {
|
||||
async fn new_payload(&self, _payload: CustomExecutionPayloadInput) -> RpcResult<PayloadStatus> {
|
||||
Ok(PayloadStatus::from_status(PayloadStatusEnum::Valid))
|
||||
}
|
||||
|
||||
async fn fork_choice_updated(
|
||||
&self,
|
||||
_fork_choice_state: ForkchoiceState,
|
||||
_payload_attributes: Option<CustomPayloadAttributes>,
|
||||
) -> RpcResult<ForkchoiceUpdated> {
|
||||
Ok(ForkchoiceUpdated {
|
||||
payload_status: PayloadStatus::from_status(PayloadStatusEnum::Valid),
|
||||
payload_id: Some(PayloadId::default()),
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_payload(
|
||||
&self,
|
||||
_payload_id: PayloadId,
|
||||
) -> RpcResult<CustomExecutionPayloadEnvelope> {
|
||||
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<N> EngineApiBuilder<N> 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<Self::EngineApi> {
|
||||
Ok(CustomEngineApi {})
|
||||
}
|
||||
}
|
||||
@@ -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 = <OpNode as NodeTypes>::StateCommitment;
|
||||
type Storage = <OpNode as NodeTypes>::Storage;
|
||||
type Payload = CustomEngineTypes;
|
||||
type Payload = CustomPayloadTypes;
|
||||
}
|
||||
|
||||
impl<N> Node<N> for CustomNode
|
||||
where
|
||||
N: FullNodeTypes<
|
||||
Types: NodeTypes<
|
||||
Payload = CustomEngineTypes,
|
||||
Payload = CustomPayloadTypes,
|
||||
ChainSpec = CustomChainSpec,
|
||||
Primitives = CustomNodePrimitives,
|
||||
Storage = OpStorage,
|
||||
|
||||
Reference in New Issue
Block a user