mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-19 03:04:27 -05:00
perf(engine): overlap block conversion with execution in payload validation (#21957)
Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
10c6bdb5ff
commit
02513ecf3b
@@ -326,9 +326,41 @@ where
|
||||
mut ctx: TreeCtx<'_, N>,
|
||||
) -> ValidationOutcome<N, InsertPayloadError<N::Block>>
|
||||
where
|
||||
V: PayloadValidator<T, Block = N::Block>,
|
||||
V: PayloadValidator<T, Block = N::Block> + Clone,
|
||||
Evm: ConfigureEngineEvm<T::ExecutionData, Primitives = N>,
|
||||
{
|
||||
// Spawn block conversion on a background thread so it runs concurrently with the
|
||||
// rest of the function (setup + execution). For payloads this overlaps the cost of
|
||||
// RLP decoding + header hashing; for already-converted blocks this is a no-op.
|
||||
let convert_to_block = match &input {
|
||||
BlockOrPayload::Payload(_) => {
|
||||
let payload_clone = input.clone();
|
||||
let validator = self.validator.clone();
|
||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||
self.payload_processor.executor().spawn_blocking(move || {
|
||||
let BlockOrPayload::Payload(payload) = payload_clone else { unreachable!() };
|
||||
let _ = tx.send(validator.convert_payload_to_block(payload));
|
||||
});
|
||||
Either::Left(rx)
|
||||
}
|
||||
BlockOrPayload::Block(_) => Either::Right(()),
|
||||
};
|
||||
|
||||
// Returns the sealed block, either by awaiting the background conversion task (for
|
||||
// payloads) or by extracting the already-converted block directly.
|
||||
let convert_to_block =
|
||||
move |input: BlockOrPayload<T>| -> Result<SealedBlock<N::Block>, NewPayloadError> {
|
||||
match convert_to_block {
|
||||
Either::Left(rx) => rx.blocking_recv().map_err(|_| {
|
||||
NewPayloadError::Other("block conversion task panicked".into())
|
||||
})?,
|
||||
Either::Right(()) => {
|
||||
let BlockOrPayload::Block(block) = input else { unreachable!() };
|
||||
Ok(block)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// A helper macro that returns the block in case there was an error
|
||||
/// This macro is used for early returns before block conversion
|
||||
macro_rules! ensure_ok {
|
||||
@@ -336,7 +368,7 @@ where
|
||||
match $expr {
|
||||
Ok(val) => val,
|
||||
Err(e) => {
|
||||
let block = self.convert_to_block(input)?;
|
||||
let block = convert_to_block(input)?;
|
||||
return Err(InsertBlockError::new(block, e.into()).into())
|
||||
}
|
||||
}
|
||||
@@ -367,7 +399,7 @@ where
|
||||
else {
|
||||
// this is pre-validated in the tree
|
||||
return Err(InsertBlockError::new(
|
||||
self.convert_to_block(input)?,
|
||||
convert_to_block(input)?,
|
||||
ProviderError::HeaderNotFound(parent_hash.into()).into(),
|
||||
)
|
||||
.into())
|
||||
@@ -380,7 +412,7 @@ where
|
||||
let Some(parent_block) = ensure_ok!(self.sealed_header_by_hash(parent_hash, ctx.state()))
|
||||
else {
|
||||
return Err(InsertBlockError::new(
|
||||
self.convert_to_block(input)?,
|
||||
convert_to_block(input)?,
|
||||
ProviderError::HeaderNotFound(parent_hash.into()).into(),
|
||||
)
|
||||
.into())
|
||||
@@ -473,7 +505,7 @@ where
|
||||
// needed. This frees up resources while state root computation continues.
|
||||
let valid_block_tx = handle.terminate_caching(Some(output.clone()));
|
||||
|
||||
let block = self.convert_to_block(input)?.with_senders(senders);
|
||||
let block = convert_to_block(input)?.with_senders(senders);
|
||||
|
||||
// Wait for the receipt root computation to complete.
|
||||
let receipt_root_bloom = receipt_root_rx
|
||||
@@ -1541,7 +1573,7 @@ where
|
||||
+ Clone
|
||||
+ 'static,
|
||||
N: NodePrimitives,
|
||||
V: PayloadValidator<Types, Block = N::Block>,
|
||||
V: PayloadValidator<Types, Block = N::Block> + Clone,
|
||||
Evm: ConfigureEngineEvm<Types::ExecutionData, Primitives = N> + 'static,
|
||||
Types: PayloadTypes<BuiltPayload: BuiltPayload<Primitives = N>>,
|
||||
{
|
||||
@@ -1595,7 +1627,7 @@ where
|
||||
}
|
||||
|
||||
/// Enum representing either block or payload being validated.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BlockOrPayload<T: PayloadTypes> {
|
||||
/// Payload.
|
||||
Payload(T::ExecutionData),
|
||||
|
||||
@@ -1327,9 +1327,9 @@ where
|
||||
>,
|
||||
EV: PayloadValidatorBuilder<Node>,
|
||||
EV::Validator: reth_engine_primitives::PayloadValidator<
|
||||
<Node::Types as NodeTypes>::Payload,
|
||||
Block = BlockTy<Node::Types>,
|
||||
>,
|
||||
<Node::Types as NodeTypes>::Payload,
|
||||
Block = BlockTy<Node::Types>,
|
||||
> + Clone,
|
||||
{
|
||||
type EngineValidator = BasicEngineValidator<Node::Provider, Node::Evm, EV::Validator>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user