chore: simplify PayloadBuilder trait (#14246)

This commit is contained in:
Arsenii Kulikov
2025-02-06 03:20:31 +04:00
committed by GitHub
parent f80d8f25f9
commit 62a8e62c3d
14 changed files with 188 additions and 279 deletions

View File

@ -16,7 +16,6 @@ workspace = true
reth-chainspec.workspace = true
reth-primitives.workspace = true
reth-primitives-traits.workspace = true
reth-transaction-pool.workspace = true
reth-provider.workspace = true
reth-payload-builder.workspace = true
reth-payload-builder-primitives.workspace = true

View File

@ -24,7 +24,6 @@ use reth_primitives_traits::proofs;
use reth_provider::{BlockReaderIdExt, CanonStateNotification, StateProviderFactory};
use reth_revm::{cached::CachedReads, cancelled::CancelOnDrop};
use reth_tasks::TaskSpawner;
use reth_transaction_pool::TransactionPool;
use revm::{Database, State};
use std::{
fmt,
@ -48,11 +47,9 @@ pub use stack::PayloadBuilderStack;
/// The [`PayloadJobGenerator`] that creates [`BasicPayloadJob`]s.
#[derive(Debug)]
pub struct BasicPayloadJobGenerator<Client, Pool, Tasks, Builder> {
pub struct BasicPayloadJobGenerator<Client, Tasks, Builder> {
/// The client that can interact with the chain.
client: Client,
/// The transaction pool to pull transactions from.
pool: Pool,
/// The task executor to spawn payload building tasks on.
executor: Tasks,
/// The configuration for the job generator.
@ -69,19 +66,17 @@ pub struct BasicPayloadJobGenerator<Client, Pool, Tasks, Builder> {
// === impl BasicPayloadJobGenerator ===
impl<Client, Pool, Tasks, Builder> BasicPayloadJobGenerator<Client, Pool, Tasks, Builder> {
impl<Client, Tasks, Builder> BasicPayloadJobGenerator<Client, Tasks, Builder> {
/// Creates a new [`BasicPayloadJobGenerator`] with the given config and custom
/// [`PayloadBuilder`]
pub fn with_builder(
client: Client,
pool: Pool,
executor: Tasks,
config: BasicPayloadJobGeneratorConfig,
builder: Builder,
) -> Self {
Self {
client,
pool,
executor,
payload_task_guard: PayloadTaskGuard::new(config.max_payload_tasks),
config,
@ -129,21 +124,20 @@ impl<Client, Pool, Tasks, Builder> BasicPayloadJobGenerator<Client, Pool, Tasks,
// === impl BasicPayloadJobGenerator ===
impl<Client, Pool, Tasks, Builder> PayloadJobGenerator
for BasicPayloadJobGenerator<Client, Pool, Tasks, Builder>
impl<Client, Tasks, Builder> PayloadJobGenerator
for BasicPayloadJobGenerator<Client, Tasks, Builder>
where
Client: StateProviderFactory
+ BlockReaderIdExt<Header = alloy_consensus::Header>
+ Clone
+ Unpin
+ 'static,
Pool: TransactionPool + Unpin + 'static,
Tasks: TaskSpawner + Clone + Unpin + 'static,
Builder: PayloadBuilder<Pool, Client> + Unpin + 'static,
<Builder as PayloadBuilder<Pool, Client>>::Attributes: Unpin + Clone,
<Builder as PayloadBuilder<Pool, Client>>::BuiltPayload: Unpin + Clone,
Builder: PayloadBuilder + Unpin + 'static,
Builder::Attributes: Unpin + Clone,
Builder::BuiltPayload: Unpin + Clone,
{
type Job = BasicPayloadJob<Client, Pool, Tasks, Builder>;
type Job = BasicPayloadJob<Tasks, Builder>;
fn new_payload_job(
&self,
@ -172,8 +166,6 @@ where
let mut job = BasicPayloadJob {
config,
client: self.client.clone(),
pool: self.pool.clone(),
executor: self.executor.clone(),
deadline,
// ticks immediately
@ -306,16 +298,12 @@ impl Default for BasicPayloadJobGeneratorConfig {
/// built and this future will wait to be resolved: [`PayloadJob::resolve`] or terminated if the
/// deadline is reached..
#[derive(Debug)]
pub struct BasicPayloadJob<Client, Pool, Tasks, Builder>
pub struct BasicPayloadJob<Tasks, Builder>
where
Builder: PayloadBuilder<Pool, Client>,
Builder: PayloadBuilder,
{
/// The configuration for how the payload will be created.
config: PayloadConfig<Builder::Attributes>,
/// The client that can interact with the chain.
client: Client,
/// The transaction pool.
pool: Pool,
/// How to spawn building tasks
executor: Tasks,
/// The deadline when this job should resolve.
@ -341,21 +329,17 @@ where
builder: Builder,
}
impl<Client, Pool, Tasks, Builder> BasicPayloadJob<Client, Pool, Tasks, Builder>
impl<Tasks, Builder> BasicPayloadJob<Tasks, Builder>
where
Client: StateProviderFactory + Clone + Unpin + 'static,
Pool: TransactionPool + Unpin + 'static,
Tasks: TaskSpawner + Clone + 'static,
Builder: PayloadBuilder<Pool, Client> + Unpin + 'static,
<Builder as PayloadBuilder<Pool, Client>>::Attributes: Unpin + Clone,
<Builder as PayloadBuilder<Pool, Client>>::BuiltPayload: Unpin + Clone,
Builder: PayloadBuilder + Unpin + 'static,
Builder::Attributes: Unpin + Clone,
Builder::BuiltPayload: Unpin + Clone,
{
/// Spawns a new payload build task.
fn spawn_build_job(&mut self) {
trace!(target: "payload_builder", id = %self.config.payload_id(), "spawn new payload build task");
let (tx, rx) = oneshot::channel();
let client = self.client.clone();
let pool = self.pool.clone();
let cancel = CancelOnDrop::default();
let _cancel = cancel.clone();
let guard = self.payload_task_guard.clone();
@ -367,14 +351,8 @@ where
self.executor.spawn_blocking(Box::pin(async move {
// acquire the permit for executing the task
let _permit = guard.acquire().await;
let args = BuildArguments {
client,
pool,
cached_reads,
config: payload_config,
cancel,
best_payload,
};
let args =
BuildArguments { cached_reads, config: payload_config, cancel, best_payload };
let result = builder.try_build(args);
let _ = tx.send(result);
}));
@ -383,14 +361,12 @@ where
}
}
impl<Client, Pool, Tasks, Builder> Future for BasicPayloadJob<Client, Pool, Tasks, Builder>
impl<Tasks, Builder> Future for BasicPayloadJob<Tasks, Builder>
where
Client: StateProviderFactory + Clone + Unpin + 'static,
Pool: TransactionPool + Unpin + 'static,
Tasks: TaskSpawner + Clone + 'static,
Builder: PayloadBuilder<Pool, Client> + Unpin + 'static,
<Builder as PayloadBuilder<Pool, Client>>::Attributes: Unpin + Clone,
<Builder as PayloadBuilder<Pool, Client>>::BuiltPayload: Unpin + Clone,
Builder: PayloadBuilder + Unpin + 'static,
Builder::Attributes: Unpin + Clone,
Builder::BuiltPayload: Unpin + Clone,
{
type Output = Result<(), PayloadBuilderError>;
@ -448,14 +424,12 @@ where
}
}
impl<Client, Pool, Tasks, Builder> PayloadJob for BasicPayloadJob<Client, Pool, Tasks, Builder>
impl<Tasks, Builder> PayloadJob for BasicPayloadJob<Tasks, Builder>
where
Client: StateProviderFactory + Clone + Unpin + 'static,
Pool: TransactionPool + Unpin + 'static,
Tasks: TaskSpawner + Clone + 'static,
Builder: PayloadBuilder<Pool, Client> + Unpin + 'static,
<Builder as PayloadBuilder<Pool, Client>>::Attributes: Unpin + Clone,
<Builder as PayloadBuilder<Pool, Client>>::BuiltPayload: Unpin + Clone,
Builder: PayloadBuilder + Unpin + 'static,
Builder::Attributes: Unpin + Clone,
Builder::BuiltPayload: Unpin + Clone,
{
type PayloadAttributes = Builder::Attributes;
type ResolvePayloadFuture = ResolveBestPayload<Self::BuiltPayload>;
@ -472,7 +446,7 @@ where
// started right away and the first full block should have been
// built by the time CL is requesting the payload.
self.metrics.inc_requested_empty_payload();
self.builder.build_empty_payload(&self.client, self.config.clone())
self.builder.build_empty_payload(self.config.clone())
}
}
@ -497,8 +471,6 @@ where
debug!(target: "payload_builder", id=%self.config.payload_id(), "no best payload yet to resolve, building empty payload");
let args = BuildArguments {
client: self.client.clone(),
pool: self.pool.clone(),
cached_reads: self.cached_reads.take().unwrap_or_default(),
config: self.config.clone(),
cancel: CancelOnDrop::default(),
@ -516,11 +488,10 @@ where
self.metrics.inc_requested_empty_payload();
// no payload built yet, so we need to return an empty payload
let (tx, rx) = oneshot::channel();
let client = self.client.clone();
let config = self.config.clone();
let builder = self.builder.clone();
self.executor.spawn_blocking(Box::pin(async move {
let res = builder.build_empty_payload(&client, config);
let res = builder.build_empty_payload(config);
let _ = tx.send(res);
}));
@ -806,13 +777,7 @@ impl<Payload> BuildOutcomeKind<Payload> {
/// building process. It holds references to the Ethereum client, transaction pool, cached reads,
/// payload configuration, cancellation status, and the best payload achieved so far.
#[derive(Debug)]
pub struct BuildArguments<Pool, Client, Attributes, Payload> {
/// How to interact with the chain.
pub client: Client,
/// The transaction pool.
///
/// Or the type that provides the transactions to build the payload.
pub pool: Pool,
pub struct BuildArguments<Attributes, Payload> {
/// Previously cached disk reads
pub cached_reads: CachedReads,
/// How to configure the payload.
@ -823,44 +788,15 @@ pub struct BuildArguments<Pool, Client, Attributes, Payload> {
pub best_payload: Option<Payload>,
}
impl<Pool, Client, Attributes, Payload> BuildArguments<Pool, Client, Attributes, Payload> {
impl<Attributes, Payload> BuildArguments<Attributes, Payload> {
/// Create new build arguments.
pub const fn new(
client: Client,
pool: Pool,
cached_reads: CachedReads,
config: PayloadConfig<Attributes>,
cancel: CancelOnDrop,
best_payload: Option<Payload>,
) -> Self {
Self { client, pool, cached_reads, config, cancel, best_payload }
}
/// Maps the transaction pool to a new type.
pub fn with_pool<P>(self, pool: P) -> BuildArguments<P, Client, Attributes, Payload> {
BuildArguments {
client: self.client,
pool,
cached_reads: self.cached_reads,
config: self.config,
cancel: self.cancel,
best_payload: self.best_payload,
}
}
/// Maps the transaction pool to a new type using a closure with the current pool type as input.
pub fn map_pool<F, P>(self, f: F) -> BuildArguments<P, Client, Attributes, Payload>
where
F: FnOnce(Pool) -> P,
{
BuildArguments {
client: self.client,
pool: f(self.pool),
cached_reads: self.cached_reads,
config: self.config,
cancel: self.cancel,
best_payload: self.best_payload,
}
Self { cached_reads, config, cancel, best_payload }
}
}
@ -872,7 +808,7 @@ impl<Pool, Client, Attributes, Payload> BuildArguments<Pool, Client, Attributes,
///
/// Generic parameters `Pool` and `Client` represent the transaction pool and
/// Ethereum client types.
pub trait PayloadBuilder<Pool, Client>: Send + Sync + Clone {
pub trait PayloadBuilder: Send + Sync + Clone {
/// The payload attributes type to accept for building.
type Attributes: PayloadBuilderAttributes;
/// The type of the built payload.
@ -892,7 +828,7 @@ pub trait PayloadBuilder<Pool, Client>: Send + Sync + Clone {
/// A `Result` indicating the build outcome or an error.
fn try_build(
&self,
args: BuildArguments<Pool, Client, Self::Attributes, Self::BuiltPayload>,
args: BuildArguments<Self::Attributes, Self::BuiltPayload>,
) -> Result<BuildOutcome<Self::BuiltPayload>, PayloadBuilderError>;
/// Invoked when the payload job is being resolved and there is no payload yet.
@ -900,7 +836,7 @@ pub trait PayloadBuilder<Pool, Client>: Send + Sync + Clone {
/// This can happen if the CL requests a payload before the first payload has been built.
fn on_missing_payload(
&self,
_args: BuildArguments<Pool, Client, Self::Attributes, Self::BuiltPayload>,
_args: BuildArguments<Self::Attributes, Self::BuiltPayload>,
) -> MissingPayloadBehaviour<Self::BuiltPayload> {
MissingPayloadBehaviour::RaceEmptyPayload
}
@ -908,7 +844,6 @@ pub trait PayloadBuilder<Pool, Client>: Send + Sync + Clone {
/// Builds an empty payload without any transaction.
fn build_empty_payload(
&self,
client: &Client,
config: PayloadConfig<Self::Attributes>,
) -> Result<Self::BuiltPayload, PayloadBuilderError>;
}

View File

@ -177,54 +177,45 @@ where
}
}
impl<L, R, Pool, Client> PayloadBuilder<Pool, Client> for PayloadBuilderStack<L, R>
impl<L, R> PayloadBuilder for PayloadBuilderStack<L, R>
where
L: PayloadBuilder<Pool, Client> + Unpin + 'static,
R: PayloadBuilder<Pool, Client> + Unpin + 'static,
Client: Clone,
Pool: Clone,
L: PayloadBuilder + Unpin + 'static,
R: PayloadBuilder + Unpin + 'static,
L::Attributes: Unpin + Clone,
R::Attributes: Unpin + Clone,
L::BuiltPayload: Unpin + Clone,
R::BuiltPayload:
BuiltPayload<Primitives = <L::BuiltPayload as BuiltPayload>::Primitives> + Unpin + Clone,
<<L as PayloadBuilder<Pool, Client>>::Attributes as PayloadBuilderAttributes>::Error: 'static,
<<R as PayloadBuilder<Pool, Client>>::Attributes as PayloadBuilderAttributes>::Error: 'static,
{
type Attributes = Either<L::Attributes, R::Attributes>;
type BuiltPayload = Either<L::BuiltPayload, R::BuiltPayload>;
fn try_build(
&self,
args: BuildArguments<Pool, Client, Self::Attributes, Self::BuiltPayload>,
args: BuildArguments<Self::Attributes, Self::BuiltPayload>,
) -> Result<BuildOutcome<Self::BuiltPayload>, PayloadBuilderError> {
match args.config.attributes {
Either::Left(ref left_attr) => {
let left_args: BuildArguments<Pool, Client, L::Attributes, L::BuiltPayload> =
BuildArguments {
client: args.client.clone(),
pool: args.pool.clone(),
cached_reads: args.cached_reads.clone(),
config: PayloadConfig {
parent_header: args.config.parent_header.clone(),
attributes: left_attr.clone(),
},
cancel: args.cancel.clone(),
best_payload: args.best_payload.clone().and_then(|payload| {
if let Either::Left(p) = payload {
Some(p)
} else {
None
}
}),
};
let left_args: BuildArguments<L::Attributes, L::BuiltPayload> = BuildArguments {
cached_reads: args.cached_reads.clone(),
config: PayloadConfig {
parent_header: args.config.parent_header.clone(),
attributes: left_attr.clone(),
},
cancel: args.cancel.clone(),
best_payload: args.best_payload.clone().and_then(|payload| {
if let Either::Left(p) = payload {
Some(p)
} else {
None
}
}),
};
self.left.try_build(left_args).map(|out| out.map_payload(Either::Left))
}
Either::Right(ref right_attr) => {
let right_args = BuildArguments {
client: args.client.clone(),
pool: args.pool.clone(),
cached_reads: args.cached_reads.clone(),
config: PayloadConfig {
parent_header: args.config.parent_header.clone(),
@ -247,7 +238,6 @@ where
fn build_empty_payload(
&self,
client: &Client,
config: PayloadConfig<Self::Attributes>,
) -> Result<Self::BuiltPayload, PayloadBuilderError> {
match config.attributes {
@ -256,14 +246,14 @@ where
parent_header: config.parent_header.clone(),
attributes: left_attr,
};
self.left.build_empty_payload(client, left_config).map(Either::Left)
self.left.build_empty_payload(left_config).map(Either::Left)
}
Either::Right(right_attr) => {
let right_config = PayloadConfig {
parent_header: config.parent_header.clone(),
attributes: right_attr,
};
self.right.build_empty_payload(client, right_config).map(Either::Right)
self.right.build_empty_payload(right_config).map(Either::Right)
}
}
}