feat: integrate payload service (#2228)

This commit is contained in:
Matthias Seitz
2023-04-13 21:25:27 +02:00
committed by GitHub
parent 9a5e15f33d
commit 0b9621cfaa
10 changed files with 150 additions and 102 deletions

View File

@ -45,17 +45,6 @@ use tokio::{
};
use tracing::trace;
// TODO move to common since commonly used
/// Settings for how to generate a block
#[derive(Debug, Clone)]
pub struct BlockConfig {
/// Data to include in the block's extra data field.
extradata: Bytes,
/// Target gas ceiling for mined blocks, defaults to 30_000_000 gas.
max_gas_limit: u64,
}
/// The [PayloadJobGenerator] that creates [BasicPayloadJob]s.
pub struct BasicPayloadJobGenerator<Client, Pool, Tasks> {
/// The client that can interact with the chain.
@ -66,8 +55,6 @@ pub struct BasicPayloadJobGenerator<Client, Pool, Tasks> {
executor: Tasks,
/// The configuration for the job generator.
config: BasicPayloadJobGeneratorConfig,
/// The configuration for how to create a block.
block_config: BlockConfig,
/// Restricts how many generator tasks can be executed at once.
payload_task_guard: PayloadTaskGuard,
/// The chain spec.
@ -83,7 +70,6 @@ impl<Client, Pool, Tasks> BasicPayloadJobGenerator<Client, Pool, Tasks> {
pool: Pool,
executor: Tasks,
config: BasicPayloadJobGeneratorConfig,
block_config: BlockConfig,
chain_spec: Arc<ChainSpec>,
) -> Self {
Self {
@ -92,7 +78,6 @@ impl<Client, Pool, Tasks> BasicPayloadJobGenerator<Client, Pool, Tasks> {
executor,
payload_task_guard: PayloadTaskGuard::new(config.max_payload_tasks),
config,
block_config,
chain_spec,
}
}
@ -128,7 +113,7 @@ where
initialized_block_env,
initialized_cfg,
parent_block: Arc::new(parent_block),
extra_data: self.block_config.extradata.clone(),
extra_data: self.config.extradata.clone(),
attributes,
chain_spec: Arc::clone(&self.chain_spec),
};
@ -167,6 +152,10 @@ impl PayloadTaskGuard {
/// Settings for the [BasicPayloadJobGenerator].
#[derive(Debug, Clone)]
pub struct BasicPayloadJobGeneratorConfig {
/// Data to include in the block's extra data field.
extradata: Bytes,
/// Target gas ceiling for mined blocks, defaults to 30_000_000 gas.
max_gas_limit: u64,
/// The interval at which the job should build a new payload after the last.
interval: Duration,
/// The deadline when this job should resolve.
@ -200,11 +189,30 @@ impl BasicPayloadJobGeneratorConfig {
self.max_payload_tasks = max_payload_tasks;
self
}
/// Sets the data to include in the block's extra data field.
///
/// Defaults to the current client version.
pub fn extradata(mut self, extradata: Bytes) -> Self {
self.extradata = extradata;
self
}
/// Sets the target gas ceiling for mined blocks.
///
/// Defaults to 30_000_000 gas.
pub fn max_gas_limit(mut self, max_gas_limit: u64) -> Self {
self.max_gas_limit = max_gas_limit;
self
}
}
impl Default for BasicPayloadJobGeneratorConfig {
fn default() -> Self {
// TODO: use default rlp client version as extradata
Self {
extradata: Default::default(),
max_gas_limit: 30_000_000,
interval: Duration::from_secs(1),
// 12s slot time
deadline: SLOT_DURATION,

View File

@ -28,5 +28,8 @@ futures-core = "0.3"
## misc
thiserror = "1.0"
sha2 = { version = "0.10", default-features = false }
parking_lot = "0.12"
tracing = "0.1.37"
[features]
test-utils = []

View File

@ -14,72 +14,18 @@
//!
//! It Defines the abstractions to create and update payloads:
//! - [PayloadJobGenerator]: a type that knows how to create new jobs for creating payloads based
//! on [PayloadAttributes].
//! on [PayloadAttributes](reth_rpc_types::engine::PayloadAttributes).
//! - [PayloadJob]: a type that can yields (better) payloads over time.
pub mod error;
mod payload;
mod service;
mod traits;
#[cfg(any(test, feature = "test-utils"))]
pub mod test_utils;
pub use payload::{BuiltPayload, PayloadBuilderAttributes};
pub use reth_rpc_types::engine::PayloadId;
pub use service::{PayloadBuilderHandle, PayloadBuilderService, PayloadStore as PayloadStore2};
pub use service::{PayloadBuilderHandle, PayloadBuilderService, PayloadStore};
pub use traits::{PayloadJob, PayloadJobGenerator};
use crate::error::PayloadBuilderError;
use parking_lot::Mutex;
use reth_primitives::{H256, U256};
use reth_rpc_types::engine::{ExecutionPayloadEnvelope, PayloadAttributes};
use std::{collections::HashMap, sync::Arc};
/// A type that has access to all locally built payloads and can create new ones.
/// This type is intended to by used by the engine API.
pub trait PayloadStore: Send + Sync {
/// Returns true if the payload store contains the given payload.
fn contains(&self, payload_id: PayloadId) -> bool;
/// Returns the current [ExecutionPayloadEnvelope] associated with the [PayloadId].
///
/// Returns `None` if the payload is not yet built, See [PayloadStore::new_payload].
fn get_execution_payload(&self, payload_id: PayloadId) -> Option<ExecutionPayloadEnvelope>;
/// Builds and stores a new payload using the given attributes.
///
/// Returns an error if the payload could not be built.
// TODO: does this require async?
fn new_payload(
&self,
parent: H256,
attributes: PayloadAttributes,
) -> Result<PayloadId, PayloadBuilderError>;
}
/// A simple in-memory payload store.
#[derive(Debug, Default)]
pub struct TestPayloadStore {
payloads: Arc<Mutex<HashMap<PayloadId, BuiltPayload>>>,
}
impl PayloadStore for TestPayloadStore {
fn contains(&self, payload_id: PayloadId) -> bool {
self.payloads.lock().contains_key(&payload_id)
}
fn get_execution_payload(&self, _payload_id: PayloadId) -> Option<ExecutionPayloadEnvelope> {
// TODO requires conversion
None
}
fn new_payload(
&self,
parent: H256,
attributes: PayloadAttributes,
) -> Result<PayloadId, PayloadBuilderError> {
let attr = PayloadBuilderAttributes::new(parent, attributes);
let payload_id = attr.payload_id();
self.payloads
.lock()
.insert(payload_id, BuiltPayload::new(payload_id, Default::default(), U256::ZERO));
Ok(payload_id)
}
}

View File

@ -53,6 +53,16 @@ impl PayloadBuilderHandle {
rx.await.ok()?
}
/// Sends a message to the service to start building a new payload for the given payload.
///
/// This is the same as [PayloadBuilderHandle::new_payload] but does not wait for the result.
pub fn send_new_payload(&self, attr: PayloadBuilderAttributes) -> PayloadId {
let id = attr.payload_id();
let (tx, _) = oneshot::channel();
let _ = self.to_service.send(PayloadServiceCommand::BuildNewPayload(attr, tx));
id
}
/// Starts building a new payload for the given payload attributes.
///
/// Returns the identifier of the payload.

View File

@ -0,0 +1,66 @@
//! Utils for testing purposes.
use crate::{
error::PayloadBuilderError, BuiltPayload, PayloadBuilderAttributes, PayloadBuilderHandle,
PayloadBuilderService, PayloadJob, PayloadJobGenerator,
};
use futures_core::Stream;
use reth_primitives::{Block, U256};
use std::{
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
/// Creates a new [PayloadBuilderService] for testing purposes.
pub fn test_payload_service(
) -> (PayloadBuilderService<TestPayloadJobGenerator>, PayloadBuilderHandle) {
PayloadBuilderService::new(Default::default())
}
/// Creates a new [PayloadBuilderService] for testing purposes and spawns it in the background.
pub fn spawn_test_payload_service() -> PayloadBuilderHandle {
let (service, handle) = test_payload_service();
tokio::spawn(service);
handle
}
/// A [PayloadJobGenerator] for testing purposes
#[derive(Debug, Default)]
#[non_exhaustive]
pub struct TestPayloadJobGenerator;
impl PayloadJobGenerator for TestPayloadJobGenerator {
type Job = TestPayloadJob;
fn new_payload_job(
&self,
attr: PayloadBuilderAttributes,
) -> Result<Self::Job, PayloadBuilderError> {
Ok(TestPayloadJob { attr })
}
}
/// A [PayloadJobGenerator] for testing purposes
#[derive(Debug)]
pub struct TestPayloadJob {
attr: PayloadBuilderAttributes,
}
impl Stream for TestPayloadJob {
type Item = Result<Arc<BuiltPayload>, PayloadBuilderError>;
fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Pending
}
}
impl PayloadJob for TestPayloadJob {
fn best_payload(&self) -> Arc<BuiltPayload> {
Arc::new(BuiltPayload::new(
self.attr.payload_id(),
Block::default().seal_slow(),
U256::ZERO,
))
}
}