reth_node_builder/components/
payload.rs

1//! Payload service component for the node builder.
2
3use crate::{BuilderContext, FullNodeTypes};
4use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
5use reth_chain_state::CanonStateSubscriptions;
6use reth_node_api::{NodeTypes, PayloadBuilderFor};
7use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
8use reth_transaction_pool::TransactionPool;
9use std::future::Future;
10
11/// A type that knows how to spawn the payload service.
12pub trait PayloadServiceBuilder<Node: FullNodeTypes, Pool: TransactionPool, EvmConfig>:
13    Send + Sized
14{
15    /// Spawns the [`PayloadBuilderService`] and returns the handle to it for use by the engine.
16    ///
17    /// We provide default implementation via [`BasicPayloadJobGenerator`] but it can be overridden
18    /// for custom job orchestration logic,
19    fn spawn_payload_builder_service(
20        self,
21        ctx: &BuilderContext<Node>,
22        pool: Pool,
23        evm_config: EvmConfig,
24    ) -> impl Future<Output = eyre::Result<PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>>>
25           + Send;
26}
27
28impl<Node, F, Fut, Pool, EvmConfig> PayloadServiceBuilder<Node, Pool, EvmConfig> for F
29where
30    Node: FullNodeTypes,
31    Pool: TransactionPool,
32    F: Fn(&BuilderContext<Node>, Pool, EvmConfig) -> Fut + Send,
33    Fut: Future<Output = eyre::Result<PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>>>
34        + Send,
35{
36    fn spawn_payload_builder_service(
37        self,
38        ctx: &BuilderContext<Node>,
39        pool: Pool,
40        evm_config: EvmConfig,
41    ) -> impl Future<Output = eyre::Result<PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>>>
42    {
43        self(ctx, pool, evm_config)
44    }
45}
46
47/// A type that knows how to build a payload builder to plug into [`BasicPayloadServiceBuilder`].
48pub trait PayloadBuilderBuilder<Node: FullNodeTypes, Pool: TransactionPool, EvmConfig>:
49    Send + Sized
50{
51    /// Payload builder implementation.
52    type PayloadBuilder: PayloadBuilderFor<Node::Types> + Unpin + 'static;
53
54    /// Spawns the payload service and returns the handle to it.
55    ///
56    /// The [`BuilderContext`] is provided to allow access to the node's configuration.
57    fn build_payload_builder(
58        self,
59        ctx: &BuilderContext<Node>,
60        pool: Pool,
61        evm_config: EvmConfig,
62    ) -> impl Future<Output = eyre::Result<Self::PayloadBuilder>> + Send;
63}
64
65/// Basic payload service builder that spawns a [`BasicPayloadJobGenerator`]
66#[derive(Debug, Default, Clone)]
67pub struct BasicPayloadServiceBuilder<PB>(PB);
68
69impl<PB> BasicPayloadServiceBuilder<PB> {
70    /// Create a new [`BasicPayloadServiceBuilder`].
71    pub const fn new(payload_builder_builder: PB) -> Self {
72        Self(payload_builder_builder)
73    }
74}
75
76impl<Node, Pool, PB, EvmConfig> PayloadServiceBuilder<Node, Pool, EvmConfig>
77    for BasicPayloadServiceBuilder<PB>
78where
79    Node: FullNodeTypes,
80    Pool: TransactionPool,
81    EvmConfig: Send,
82    PB: PayloadBuilderBuilder<Node, Pool, EvmConfig>,
83{
84    async fn spawn_payload_builder_service(
85        self,
86        ctx: &BuilderContext<Node>,
87        pool: Pool,
88        evm_config: EvmConfig,
89    ) -> eyre::Result<PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>> {
90        let payload_builder = self.0.build_payload_builder(ctx, pool, evm_config).await?;
91
92        let conf = ctx.config().builder.clone();
93
94        let payload_job_config = BasicPayloadJobGeneratorConfig::default()
95            .interval(conf.interval)
96            .deadline(conf.deadline)
97            .max_payload_tasks(conf.max_payload_tasks);
98
99        let payload_generator = BasicPayloadJobGenerator::with_builder(
100            ctx.provider().clone(),
101            ctx.task_executor().clone(),
102            payload_job_config,
103            payload_builder,
104        );
105        let (payload_service, payload_service_handle) =
106            PayloadBuilderService::new(payload_generator, ctx.provider().canonical_state_stream());
107
108        ctx.task_executor().spawn_critical("payload builder service", Box::pin(payload_service));
109
110        Ok(payload_service_handle)
111    }
112}