reth_optimism_rpc/
witness.rs

1//! Support for optimism specific witness RPCs.
2
3use alloy_primitives::B256;
4use alloy_rpc_types_debug::ExecutionWitness;
5use jsonrpsee_core::{async_trait, RpcResult};
6use op_alloy_rpc_types_engine::OpPayloadAttributes;
7use reth_chainspec::ChainSpecProvider;
8use reth_evm::ConfigureEvm;
9use reth_node_api::NodePrimitives;
10use reth_optimism_chainspec::OpChainSpec;
11use reth_optimism_evm::OpNextBlockEnvAttributes;
12use reth_optimism_payload_builder::{OpPayloadBuilder, OpPayloadPrimitives};
13use reth_optimism_txpool::OpPooledTx;
14use reth_primitives_traits::SealedHeader;
15pub use reth_rpc_api::DebugExecutionWitnessApiServer;
16use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
17use reth_storage_api::{
18    errors::{ProviderError, ProviderResult},
19    BlockReaderIdExt, NodePrimitivesProvider, StateProviderFactory,
20};
21use reth_tasks::TaskSpawner;
22use reth_transaction_pool::TransactionPool;
23use std::{fmt::Debug, sync::Arc};
24use tokio::sync::{oneshot, Semaphore};
25
26/// An extension to the `debug_` namespace of the RPC API.
27pub struct OpDebugWitnessApi<Pool, Provider, EvmConfig> {
28    inner: Arc<OpDebugWitnessApiInner<Pool, Provider, EvmConfig>>,
29}
30
31impl<Pool, Provider, EvmConfig> OpDebugWitnessApi<Pool, Provider, EvmConfig> {
32    /// Creates a new instance of the `OpDebugWitnessApi`.
33    pub fn new(
34        provider: Provider,
35        task_spawner: Box<dyn TaskSpawner>,
36        builder: OpPayloadBuilder<Pool, Provider, EvmConfig>,
37    ) -> Self {
38        let semaphore = Arc::new(Semaphore::new(3));
39        let inner = OpDebugWitnessApiInner { provider, builder, task_spawner, semaphore };
40        Self { inner: Arc::new(inner) }
41    }
42}
43
44impl<Pool, Provider, EvmConfig> OpDebugWitnessApi<Pool, Provider, EvmConfig>
45where
46    EvmConfig: ConfigureEvm,
47    Provider: NodePrimitivesProvider + BlockReaderIdExt<Header = alloy_consensus::Header>,
48{
49    /// Fetches the parent header by hash.
50    fn parent_header(&self, parent_block_hash: B256) -> ProviderResult<SealedHeader> {
51        self.inner
52            .provider
53            .sealed_header_by_hash(parent_block_hash)?
54            .ok_or_else(|| ProviderError::HeaderNotFound(parent_block_hash.into()))
55    }
56}
57
58#[async_trait]
59impl<Pool, Provider, EvmConfig> DebugExecutionWitnessApiServer<OpPayloadAttributes>
60    for OpDebugWitnessApi<Pool, Provider, EvmConfig>
61where
62    Pool: TransactionPool<
63            Transaction: OpPooledTx<Consensus = <Provider::Primitives as NodePrimitives>::SignedTx>,
64        > + 'static,
65    Provider: BlockReaderIdExt<Header = alloy_consensus::Header>
66        + NodePrimitivesProvider<Primitives: OpPayloadPrimitives>
67        + StateProviderFactory
68        + ChainSpecProvider<ChainSpec = OpChainSpec>
69        + Clone
70        + 'static,
71    EvmConfig: ConfigureEvm<Primitives = Provider::Primitives, NextBlockEnvCtx = OpNextBlockEnvAttributes>
72        + 'static,
73{
74    async fn execute_payload(
75        &self,
76        parent_block_hash: B256,
77        attributes: OpPayloadAttributes,
78    ) -> RpcResult<ExecutionWitness> {
79        let _permit = self.inner.semaphore.acquire().await;
80
81        let parent_header = self.parent_header(parent_block_hash).to_rpc_result()?;
82
83        let (tx, rx) = oneshot::channel();
84        let this = self.clone();
85        self.inner.task_spawner.spawn_blocking(Box::pin(async move {
86            let res = this.inner.builder.payload_witness(parent_header, attributes);
87            let _ = tx.send(res);
88        }));
89
90        rx.await
91            .map_err(|err| internal_rpc_err(err.to_string()))?
92            .map_err(|err| internal_rpc_err(err.to_string()))
93    }
94}
95
96impl<Pool, Provider, EvmConfig> Clone for OpDebugWitnessApi<Pool, Provider, EvmConfig> {
97    fn clone(&self) -> Self {
98        Self { inner: Arc::clone(&self.inner) }
99    }
100}
101impl<Pool, Provider, EvmConfig> Debug for OpDebugWitnessApi<Pool, Provider, EvmConfig> {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        f.debug_struct("OpDebugWitnessApi").finish_non_exhaustive()
104    }
105}
106
107struct OpDebugWitnessApiInner<Pool, Provider, EvmConfig> {
108    provider: Provider,
109    builder: OpPayloadBuilder<Pool, Provider, EvmConfig>,
110    task_spawner: Box<dyn TaskSpawner>,
111    semaphore: Arc<Semaphore>,
112}