Files
reth/examples/custom-payload-builder/src/generator.rs
2024-02-01 12:26:18 +00:00

97 lines
3.5 KiB
Rust

use crate::job::EmptyBlockPayloadJob;
use reth::{
providers::{BlockReaderIdExt, BlockSource, StateProviderFactory},
tasks::TaskSpawner,
transaction_pool::TransactionPool,
};
use reth_basic_payload_builder::{BasicPayloadJobGeneratorConfig, PayloadBuilder, PayloadConfig};
use reth_node_api::PayloadBuilderAttributes;
use reth_payload_builder::{error::PayloadBuilderError, PayloadJobGenerator};
use reth_primitives::{BlockNumberOrTag, Bytes, ChainSpec};
use std::sync::Arc;
/// The generator type that creates new jobs that builds empty blocks.
#[derive(Debug)]
pub struct EmptyBlockPayloadJobGenerator<Client, Pool, Tasks, Builder> {
/// The client that can interact with the chain.
client: Client,
/// txpool
pool: Pool,
/// How to spawn building tasks
executor: Tasks,
/// The configuration for the job generator.
_config: BasicPayloadJobGeneratorConfig,
/// The chain spec.
chain_spec: Arc<ChainSpec>,
/// The type responsible for building payloads.
///
/// See [PayloadBuilder]
builder: Builder,
}
// === impl EmptyBlockPayloadJobGenerator ===
impl<Client, Pool, Tasks, Builder> EmptyBlockPayloadJobGenerator<Client, Pool, Tasks, Builder> {
/// Creates a new [EmptyBlockPayloadJobGenerator] with the given config and custom
/// [PayloadBuilder]
pub fn with_builder(
client: Client,
pool: Pool,
executor: Tasks,
config: BasicPayloadJobGeneratorConfig,
chain_spec: Arc<ChainSpec>,
builder: Builder,
) -> Self {
Self { client, pool, executor, _config: config, builder, chain_spec }
}
}
impl<Client, Pool, Tasks, Builder> PayloadJobGenerator
for EmptyBlockPayloadJobGenerator<Client, Pool, Tasks, Builder>
where
Client: StateProviderFactory + BlockReaderIdExt + 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,
{
type Job = EmptyBlockPayloadJob<Client, Pool, Tasks, Builder>;
/// This is invoked when the node receives payload attributes from the beacon node via
/// `engine_forkchoiceUpdatedV1`
fn new_payload_job(
&self,
attributes: <Builder as PayloadBuilder<Pool, Client>>::Attributes,
) -> Result<Self::Job, PayloadBuilderError> {
let parent_block = if attributes.parent().is_zero() {
// use latest block if parent is zero: genesis block
self.client
.block_by_number_or_tag(BlockNumberOrTag::Latest)?
.ok_or_else(|| PayloadBuilderError::MissingParentBlock(attributes.parent()))?
.seal_slow()
} else {
let block = self
.client
.find_block_by_hash(attributes.parent(), BlockSource::Any)?
.ok_or_else(|| PayloadBuilderError::MissingParentBlock(attributes.parent()))?;
// we already know the hash, so we can seal it
block.seal(attributes.parent())
};
let config = PayloadConfig::new(
Arc::new(parent_block),
Bytes::default(),
attributes,
Arc::clone(&self.chain_spec),
);
Ok(EmptyBlockPayloadJob {
client: self.client.clone(),
_pool: self.pool.clone(),
_executor: self.executor.clone(),
_builder: self.builder.clone(),
config,
})
}
}