Skip to content

Commit 6f8082a

Browse files
authored
feat(examples): add custom engine API to custom-node example (paradigmxyz#15436)
1 parent 69df27e commit 6f8082a

File tree

5 files changed

+111
-94
lines changed

5 files changed

+111
-94
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/custom-node/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ reth-optimism-forks.workspace = true
1818
reth-optimism-node.workspace = true
1919
reth-optimism-primitives = { workspace = true, features = ["serde", "reth-codec"] }
2020
reth-primitives-traits.workspace = true
21+
reth-rpc-api.workspace = true
2122

2223
# revm
2324
revm-primitives.workspace = true
@@ -33,8 +34,11 @@ op-alloy-consensus.workspace = true
3334
op-alloy-rpc-types-engine.workspace = true
3435

3536
# misc
37+
async-trait.workspace = true
3638
derive_more.workspace = true
39+
eyre.workspace = true
3740
serde.workspace = true
41+
jsonrpsee.workspace = true
3842

3943
[features]
4044
default = []

examples/custom-node/src/engine.rs

Lines changed: 5 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
use crate::primitives::CustomNodePrimitives;
2-
use alloy_rpc_types_engine::{
3-
BlobsBundleV1, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3,
4-
};
5-
use op_alloy_rpc_types_engine::{
6-
OpExecutionData, OpExecutionPayload, OpExecutionPayloadEnvelopeV3,
7-
OpExecutionPayloadEnvelopeV4, OpExecutionPayloadV4,
8-
};
2+
use op_alloy_rpc_types_engine::{OpExecutionData, OpExecutionPayload};
93
use reth_chain_state::ExecutedBlockWithTrieUpdates;
104
use reth_node_api::{
11-
BuiltPayload, EngineTypes, ExecutionPayload, NodePrimitives, PayloadAttributes,
12-
PayloadBuilderAttributes, PayloadTypes,
5+
BuiltPayload, ExecutionPayload, NodePrimitives, PayloadAttributes, PayloadBuilderAttributes,
6+
PayloadTypes,
137
};
148
use reth_optimism_node::{OpBuiltPayload, OpPayloadAttributes, OpPayloadBuilderAttributes};
159
use reth_optimism_primitives::OpTransactionSigned;
1610
use reth_primitives_traits::SealedBlock;
1711
use revm_primitives::U256;
1812
use serde::{Deserialize, Serialize};
19-
use std::sync::Arc;
2013

2114
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
22-
pub struct CustomEngineTypes;
15+
pub struct CustomPayloadTypes;
2316

2417
#[derive(Debug, Clone, Serialize, Deserialize)]
2518
pub struct CustomExecutionData {
@@ -164,79 +157,7 @@ impl From<CustomBuiltPayload>
164157
}
165158
}
166159

167-
impl From<CustomBuiltPayload> for ExecutionPayloadV1 {
168-
fn from(value: CustomBuiltPayload) -> Self {
169-
Self::from_block_unchecked(value.block().hash(), &value.into())
170-
}
171-
}
172-
173-
impl From<CustomBuiltPayload> for ExecutionPayloadV2 {
174-
fn from(value: CustomBuiltPayload) -> Self {
175-
Self::from_block_unchecked(value.block().hash(), &value.into())
176-
}
177-
}
178-
179-
impl From<CustomBuiltPayload> for OpExecutionPayloadEnvelopeV3 {
180-
fn from(value: CustomBuiltPayload) -> Self {
181-
Self {
182-
block_value: value.fees(),
183-
// From the engine API spec:
184-
//
185-
// > Client software **MAY** use any heuristics to decide whether to set
186-
// `shouldOverrideBuilder` flag or not. If client software does not implement any
187-
// heuristic this flag **SHOULD** be set to `false`.
188-
//
189-
// Spec:
190-
// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification-2>
191-
should_override_builder: false,
192-
// No blobs for OP.
193-
blobs_bundle: BlobsBundleV1 { blobs: vec![], commitments: vec![], proofs: vec![] },
194-
parent_beacon_block_root: value.0.block().parent_beacon_block_root.unwrap_or_default(),
195-
execution_payload: ExecutionPayloadV3::from_block_unchecked(
196-
value.0.block().hash(),
197-
&value.into(),
198-
),
199-
}
200-
}
201-
}
202-
203-
impl From<CustomBuiltPayload> for OpExecutionPayloadEnvelopeV4 {
204-
fn from(value: CustomBuiltPayload) -> Self {
205-
let fees = value.0.fees();
206-
let block = value.0.into_sealed_block();
207-
208-
let parent_beacon_block_root = block.parent_beacon_block_root.unwrap_or_default();
209-
210-
let l2_withdrawals_root = block.withdrawals_root.unwrap_or_default();
211-
let payload_v3 = ExecutionPayloadV3::from_block_unchecked(
212-
block.hash(),
213-
&Arc::unwrap_or_clone(block.into()).into_block(),
214-
);
215-
216-
Self {
217-
execution_payload: OpExecutionPayloadV4::from_v3_with_withdrawals_root(
218-
payload_v3,
219-
l2_withdrawals_root,
220-
),
221-
block_value: fees,
222-
// From the engine API spec:
223-
//
224-
// > Client software **MAY** use any heuristics to decide whether to set
225-
// `shouldOverrideBuilder` flag or not. If client software does not implement any
226-
// heuristic this flag **SHOULD** be set to `false`.
227-
//
228-
// Spec:
229-
// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification-2>
230-
should_override_builder: false,
231-
// No blobs for OP.
232-
blobs_bundle: BlobsBundleV1 { blobs: vec![], commitments: vec![], proofs: vec![] },
233-
parent_beacon_block_root,
234-
execution_requests: vec![],
235-
}
236-
}
237-
}
238-
239-
impl PayloadTypes for CustomEngineTypes {
160+
impl PayloadTypes for CustomPayloadTypes {
240161
type BuiltPayload = CustomBuiltPayload;
241162
type PayloadAttributes = CustomPayloadAttributes;
242163
type PayloadBuilderAttributes = CustomPayloadBuilderAttributes;
@@ -254,10 +175,3 @@ impl PayloadTypes for CustomEngineTypes {
254175
CustomExecutionData { inner: OpExecutionData { payload, sidecar }, extension }
255176
}
256177
}
257-
258-
impl EngineTypes for CustomEngineTypes {
259-
type ExecutionPayloadEnvelopeV1 = ExecutionPayloadV1;
260-
type ExecutionPayloadEnvelopeV2 = ExecutionPayloadV2;
261-
type ExecutionPayloadEnvelopeV3 = OpExecutionPayloadEnvelopeV3;
262-
type ExecutionPayloadEnvelopeV4 = OpExecutionPayloadEnvelopeV4;
263-
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use crate::{
2+
chainspec::CustomChainSpec,
3+
engine::{CustomPayloadAttributes, CustomPayloadTypes},
4+
primitives::CustomNodePrimitives,
5+
};
6+
use alloy_rpc_types_engine::{
7+
ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, PayloadStatusEnum,
8+
};
9+
use async_trait::async_trait;
10+
use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule};
11+
use reth_node_api::{AddOnsContext, FullNodeComponents, NodeTypes};
12+
use reth_node_builder::rpc::EngineApiBuilder;
13+
use reth_optimism_node::node::OpStorage;
14+
use reth_rpc_api::IntoEngineApiRpcModule;
15+
16+
#[derive(serde::Deserialize)]
17+
pub struct CustomExecutionPayloadInput {}
18+
19+
#[derive(Clone, serde::Serialize)]
20+
pub struct CustomExecutionPayloadEnvelope {}
21+
22+
#[rpc(server, namespace = "engine")]
23+
pub trait CustomEngineApi {
24+
#[method(name = "newPayload")]
25+
async fn new_payload(&self, payload: CustomExecutionPayloadInput) -> RpcResult<PayloadStatus>;
26+
27+
#[method(name = "forkchoiceUpdated")]
28+
async fn fork_choice_updated(
29+
&self,
30+
fork_choice_state: ForkchoiceState,
31+
payload_attributes: Option<CustomPayloadAttributes>,
32+
) -> RpcResult<ForkchoiceUpdated>;
33+
34+
#[method(name = "getPayload")]
35+
async fn get_payload(&self, payload_id: PayloadId)
36+
-> RpcResult<CustomExecutionPayloadEnvelope>;
37+
}
38+
39+
pub struct CustomEngineApi {}
40+
41+
#[async_trait]
42+
impl CustomEngineApiServer for CustomEngineApi {
43+
async fn new_payload(&self, _payload: CustomExecutionPayloadInput) -> RpcResult<PayloadStatus> {
44+
Ok(PayloadStatus::from_status(PayloadStatusEnum::Valid))
45+
}
46+
47+
async fn fork_choice_updated(
48+
&self,
49+
_fork_choice_state: ForkchoiceState,
50+
_payload_attributes: Option<CustomPayloadAttributes>,
51+
) -> RpcResult<ForkchoiceUpdated> {
52+
Ok(ForkchoiceUpdated {
53+
payload_status: PayloadStatus::from_status(PayloadStatusEnum::Valid),
54+
payload_id: Some(PayloadId::default()),
55+
})
56+
}
57+
58+
async fn get_payload(
59+
&self,
60+
_payload_id: PayloadId,
61+
) -> RpcResult<CustomExecutionPayloadEnvelope> {
62+
Ok(CustomExecutionPayloadEnvelope {})
63+
}
64+
}
65+
66+
impl IntoEngineApiRpcModule for CustomEngineApi
67+
where
68+
Self: CustomEngineApiServer,
69+
{
70+
fn into_rpc_module(self) -> RpcModule<()> {
71+
self.into_rpc().remove_context()
72+
}
73+
}
74+
75+
#[derive(Debug, Default)]
76+
pub struct CustomEngineApiBuilder {}
77+
78+
impl<N> EngineApiBuilder<N> for CustomEngineApiBuilder
79+
where
80+
N: FullNodeComponents<
81+
Types: NodeTypes<
82+
Payload = CustomPayloadTypes,
83+
ChainSpec = CustomChainSpec,
84+
Primitives = CustomNodePrimitives,
85+
Storage = OpStorage,
86+
>,
87+
>,
88+
{
89+
type EngineApi = CustomEngineApi;
90+
91+
async fn build_engine_api(self, _ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
92+
Ok(CustomEngineApi {})
93+
}
94+
}

examples/custom-node/src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
99

1010
use chainspec::CustomChainSpec;
11-
use engine::CustomEngineTypes;
11+
use engine::CustomPayloadTypes;
1212
use primitives::CustomNodePrimitives;
1313
use reth_node_api::{FullNodeTypes, NodeTypes};
1414
use reth_node_builder::{components::ComponentsBuilder, Node, NodeComponentsBuilder};
@@ -19,6 +19,7 @@ use reth_optimism_node::{
1919

2020
pub mod chainspec;
2121
pub mod engine;
22+
pub mod engine_api;
2223
pub mod primitives;
2324

2425
#[derive(Debug, Clone)]
@@ -29,14 +30,14 @@ impl NodeTypes for CustomNode {
2930
type ChainSpec = CustomChainSpec;
3031
type StateCommitment = <OpNode as NodeTypes>::StateCommitment;
3132
type Storage = <OpNode as NodeTypes>::Storage;
32-
type Payload = CustomEngineTypes;
33+
type Payload = CustomPayloadTypes;
3334
}
3435

3536
impl<N> Node<N> for CustomNode
3637
where
3738
N: FullNodeTypes<
3839
Types: NodeTypes<
39-
Payload = CustomEngineTypes,
40+
Payload = CustomPayloadTypes,
4041
ChainSpec = CustomChainSpec,
4142
Primitives = CustomNodePrimitives,
4243
Storage = OpStorage,

0 commit comments

Comments
 (0)