Skip to main content

reth_payload_builder/
lib.rs

1//! This crate defines abstractions to create and update payloads (blocks):
2//! - [`PayloadJobGenerator`]: a type that knows how to create new jobs for creating payloads based
3//!   on [`PayloadAttributes`](alloy_rpc_types::engine::PayloadAttributes).
4//! - [`PayloadJob`]: a type that yields (better) payloads over time.
5//!
6//! This crate comes with the generic [`PayloadBuilderService`] responsible for managing payload
7//! jobs.
8//!
9//! ## Node integration
10//!
11//! In a standard node the [`PayloadBuilderService`] sits downstream of the engine API, or rather
12//! the component that handles requests from the consensus layer like `engine_forkchoiceUpdatedV1`.
13//!
14//! Payload building is enabled if the forkchoice update request contains payload attributes.
15//!
16//! See also [the engine API docs](https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_forkchoiceupdatedv2)
17//! If the forkchoice update request is `VALID` and contains payload attributes the
18//! [`PayloadBuilderService`] will create a new [`PayloadJob`] via the given [`PayloadJobGenerator`]
19//! and start polling it until the payload is requested by the CL and the payload job is resolved
20//! (see [`PayloadJob::resolve`]).
21//!
22//! ## Example
23//!
24//! A simple example of a [`PayloadJobGenerator`] that creates empty blocks:
25//!
26//! ```
27//! use std::future::Future;
28//! use std::pin::Pin;
29//! use std::sync::Arc;
30//! use std::task::{Context, Poll};
31//! use alloy_consensus::{Header, Block};
32//! use alloy_primitives::B256;
33//! use reth_payload_builder::PayloadId;
34//! use alloy_primitives::U256;
35//! use reth_payload_builder::{EthBuiltPayload, PayloadBuilderError, KeepPayloadJobAlive, PayloadJob, PayloadJobGenerator, PayloadKind};
36//! use reth_primitives_traits::SealedBlock;
37//! use alloy_rpc_types::engine::PayloadAttributes;
38//!
39//! /// The generator type that creates new jobs that builds empty blocks.
40//! pub struct EmptyBlockPayloadJobGenerator;
41//!
42//! impl PayloadJobGenerator for EmptyBlockPayloadJobGenerator {
43//!     type Job = EmptyBlockPayloadJob;
44//!
45//! /// This is invoked when the node receives payload attributes from the beacon node via `engine_forkchoiceUpdatedV1`
46//! fn new_payload_job(&self, parent: B256, attr: PayloadAttributes, _id: PayloadId) -> Result<Self::Job, PayloadBuilderError> {
47//!         Ok(EmptyBlockPayloadJob{ attributes: attr, parent })
48//!     }
49//!
50//! }
51//!
52//! /// A [PayloadJob] that builds empty blocks.
53//! pub struct EmptyBlockPayloadJob {
54//!   attributes: PayloadAttributes,
55//!   parent: B256,
56//! }
57//!
58//! impl PayloadJob for EmptyBlockPayloadJob {
59//!    type PayloadAttributes = PayloadAttributes;
60//!    type ResolvePayloadFuture = futures_util::future::Ready<Result<EthBuiltPayload, PayloadBuilderError>>;
61//!    type BuiltPayload = EthBuiltPayload;
62//!
63//! fn best_payload(&self) -> Result<EthBuiltPayload, PayloadBuilderError> {
64//!     // NOTE: some fields are omitted here for brevity
65//!     let block = Block {
66//!         header: Header {
67//!             parent_hash: self.parent,
68//!             timestamp: self.attributes.timestamp,
69//!             beneficiary: self.attributes.suggested_fee_recipient,
70//!             ..Default::default()
71//!         },
72//!         ..Default::default()
73//!     };
74//!     let payload = EthBuiltPayload::new(Arc::new(SealedBlock::seal_slow(block)), U256::ZERO, None);
75//!     Ok(payload)
76//! }
77//!
78//! fn payload_attributes(&self) -> Result<PayloadAttributes, PayloadBuilderError> {
79//!     Ok(self.attributes.clone())
80//! }
81//!
82//! fn payload_timestamp(&self) -> Result<u64, PayloadBuilderError> {
83//!     Ok(self.attributes.timestamp)
84//! }
85//!
86//! fn resolve_kind(&mut self, _kind: PayloadKind) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) {
87//!        let payload = self.best_payload();
88//!        (futures_util::future::ready(payload), KeepPayloadJobAlive::No)
89//!     }
90//! }
91//!
92//! /// A [PayloadJob] is a future that's being polled by the `PayloadBuilderService`
93//! impl Future for EmptyBlockPayloadJob {
94//!  type Output = Result<(), PayloadBuilderError>;
95//!
96//! fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
97//!         Poll::Pending
98//!     }
99//! }
100//! ```
101//!
102//! ## Feature Flags
103//!
104//! - `test-utils`: Export utilities for testing
105
106#![doc(
107    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
108    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
109    issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
110)]
111#![cfg_attr(not(test), warn(unused_crate_dependencies))]
112#![cfg_attr(docsrs, feature(doc_cfg))]
113
114mod metrics;
115mod service;
116mod traits;
117
118pub mod noop;
119
120#[cfg(any(test, feature = "test-utils"))]
121pub mod test_utils;
122
123pub use alloy_rpc_types::engine::PayloadId;
124pub use reth_payload_builder_primitives::PayloadBuilderError;
125pub use reth_payload_primitives::PayloadKind;
126pub use service::{
127    PayloadBuilderHandle, PayloadBuilderService, PayloadServiceCommand, PayloadStore,
128};
129pub use traits::{KeepPayloadJobAlive, PayloadJob, PayloadJobGenerator};
130
131// re-export the Ethereum engine primitives for convenience
132#[doc(inline)]
133pub use reth_ethereum_engine_primitives::{BlobSidecars, EthBuiltPayload};