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