Skip to main content

reth_payload_builder/
traits.rs

1//! Trait abstractions used by the payload crate.
2
3use alloy_primitives::B256;
4use alloy_rpc_types::engine::PayloadId;
5use reth_chain_state::CanonStateNotification;
6use reth_payload_builder_primitives::PayloadBuilderError;
7use reth_payload_primitives::{BuiltPayload, PayloadAttributes, PayloadKind};
8use reth_primitives_traits::NodePrimitives;
9use std::future::Future;
10
11/// A type that can build a payload.
12///
13/// This type is a [`Future`] that resolves when the job is done (e.g. complete, timed out) or it
14/// failed. It's not supposed to return the best payload built when it resolves, instead
15/// [`PayloadJob::best_payload`] should be used for that.
16///
17/// A `PayloadJob` must always be prepared to return the best payload built so far to ensure there
18/// is a valid payload to deliver to the CL, so it does not miss a slot, even if the payload is
19/// empty.
20///
21/// Note: A `PayloadJob` need to be cancel safe because it might be dropped after the CL has requested the payload via `engine_getPayloadV1` (see also [engine API docs](https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1))
22pub trait PayloadJob: Future<Output = Result<(), PayloadBuilderError>> {
23    /// Represents the payload attributes type that is used to spawn this payload job.
24    type PayloadAttributes: PayloadAttributes + std::fmt::Debug;
25    /// Represents the future that resolves the block that's returned to the CL.
26    type ResolvePayloadFuture: Future<Output = Result<Self::BuiltPayload, PayloadBuilderError>>
27        + Send
28        + 'static;
29    /// Represents the built payload type that is returned to the CL.
30    type BuiltPayload: BuiltPayload + Clone + std::fmt::Debug;
31
32    /// Returns the best payload that has been built so far.
33    ///
34    /// Note: This is never called by the CL.
35    fn best_payload(&self) -> Result<Self::BuiltPayload, PayloadBuilderError>;
36
37    /// Returns the payload attributes for the payload being built.
38    fn payload_attributes(&self) -> Result<Self::PayloadAttributes, PayloadBuilderError>;
39
40    /// Returns the payload timestamp for the payload being built.
41    /// The default implementation allocates full attributes only to
42    /// extract the timestamp. Provide your own implementation if you
43    /// need performance here.
44    fn payload_timestamp(&self) -> Result<u64, PayloadBuilderError> {
45        Ok(self.payload_attributes()?.timestamp())
46    }
47
48    /// Called when the payload is requested by the CL.
49    ///
50    /// This is invoked on [`engine_getPayloadV2`](https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#engine_getpayloadv2) and [`engine_getPayloadV1`](https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#engine_getpayloadv1).
51    ///
52    /// The timeout for returning the payload to the CL is 1s, thus the future returned should
53    /// resolve in under 1 second.
54    ///
55    /// Ideally this is the best payload built so far, or an empty block without transactions, if
56    /// nothing has been built yet.
57    ///
58    /// According to the spec:
59    /// > Client software MAY stop the corresponding build process after serving this call.
60    ///
61    /// It is at the discretion of the implementer whether the build job should be kept alive or
62    /// terminated.
63    ///
64    /// If this returns [`KeepPayloadJobAlive::Yes`], then the [`PayloadJob`] will be polled
65    /// once more. If this returns [`KeepPayloadJobAlive::No`] then the [`PayloadJob`] will be
66    /// dropped after this call.
67    ///
68    /// The [`PayloadKind`] determines how the payload should be resolved in the
69    /// `ResolvePayloadFuture`. [`PayloadKind::Earliest`] should return the earliest available
70    /// payload (as fast as possible), e.g. racing an empty payload job against a pending job if
71    /// there's no payload available yet. [`PayloadKind::WaitForPending`] is allowed to wait
72    /// until a built payload is available.
73    fn resolve_kind(
74        &mut self,
75        kind: PayloadKind,
76    ) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive);
77
78    /// Resolves the payload as fast as possible.
79    ///
80    /// See also [`PayloadJob::resolve_kind`]
81    fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) {
82        self.resolve_kind(PayloadKind::Earliest)
83    }
84}
85
86/// Whether the payload job should be kept alive or terminated after the payload was requested by
87/// the CL.
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum KeepPayloadJobAlive {
90    /// Keep the job alive.
91    Yes,
92    /// Terminate the job.
93    No,
94}
95
96/// A type that knows how to create new jobs for creating payloads.
97pub trait PayloadJobGenerator {
98    /// The type that manages the lifecycle of a payload.
99    ///
100    /// This type is a future that yields better payloads.
101    type Job: PayloadJob;
102
103    /// Creates the initial payload and a new [`PayloadJob`] that yields better payloads over time.
104    ///
105    /// This is called when the CL requests a new payload job via a fork choice update.
106    ///
107    /// # Note
108    ///
109    /// This is expected to initially build a new (empty) payload without transactions, so it can be
110    /// returned directly.
111    fn new_payload_job(
112        &self,
113        parent: B256,
114        attr: <Self::Job as PayloadJob>::PayloadAttributes,
115        id: PayloadId,
116    ) -> Result<Self::Job, PayloadBuilderError>;
117
118    /// Handles new chain state events
119    ///
120    /// This is intended for any logic that needs to be run when the chain state changes or used to
121    /// use the in memory state for the head block.
122    fn on_new_state<N: NodePrimitives>(&mut self, new_state: CanonStateNotification<N>) {
123        let _ = new_state;
124    }
125}