reth_optimism_flashblocks/
worker.rs1use crate::{ExecutionPayloadBaseV1, PendingFlashBlock};
2use alloy_eips::{eip2718::WithEncoded, BlockNumberOrTag};
3use alloy_primitives::B256;
4use reth_chain_state::{CanonStateSubscriptions, ExecutedBlock};
5use reth_errors::RethError;
6use reth_evm::{
7 execute::{BlockBuilder, BlockBuilderOutcome},
8 ConfigureEvm,
9};
10use reth_execution_types::ExecutionOutcome;
11use reth_primitives_traits::{
12 AlloyBlockHeader, BlockTy, HeaderTy, NodePrimitives, ReceiptTy, Recovered,
13};
14use reth_revm::{cached::CachedReads, database::StateProviderDatabase, db::State};
15use reth_rpc_eth_types::{EthApiError, PendingBlock};
16use reth_storage_api::{noop::NoopProvider, BlockReaderIdExt, StateProviderFactory};
17use std::{
18 sync::Arc,
19 time::{Duration, Instant},
20};
21use tracing::trace;
22
23#[derive(Debug)]
25pub(crate) struct FlashBlockBuilder<EvmConfig, Provider> {
26 evm_config: EvmConfig,
27 provider: Provider,
28}
29
30impl<EvmConfig, Provider> FlashBlockBuilder<EvmConfig, Provider> {
31 pub(crate) const fn new(evm_config: EvmConfig, provider: Provider) -> Self {
32 Self { evm_config, provider }
33 }
34
35 pub(crate) const fn provider(&self) -> &Provider {
36 &self.provider
37 }
38}
39
40pub(crate) struct BuildArgs<I> {
41 pub(crate) base: ExecutionPayloadBaseV1,
42 pub(crate) transactions: I,
43 pub(crate) cached_state: Option<(B256, CachedReads)>,
44 pub(crate) last_flashblock_index: u64,
45 pub(crate) last_flashblock_hash: B256,
46 pub(crate) compute_state_root: bool,
47}
48
49impl<N, EvmConfig, Provider> FlashBlockBuilder<EvmConfig, Provider>
50where
51 N: NodePrimitives,
52 EvmConfig: ConfigureEvm<Primitives = N, NextBlockEnvCtx: From<ExecutionPayloadBaseV1> + Unpin>,
53 Provider: StateProviderFactory
54 + CanonStateSubscriptions<Primitives = N>
55 + BlockReaderIdExt<
56 Header = HeaderTy<N>,
57 Block = BlockTy<N>,
58 Transaction = N::SignedTx,
59 Receipt = ReceiptTy<N>,
60 > + Unpin,
61{
62 pub(crate) fn execute<I: IntoIterator<Item = WithEncoded<Recovered<N::SignedTx>>>>(
67 &self,
68 mut args: BuildArgs<I>,
69 ) -> eyre::Result<Option<(PendingFlashBlock<N>, CachedReads)>> {
70 trace!("Attempting new pending block from flashblocks");
71
72 let latest = self
73 .provider
74 .latest_header()?
75 .ok_or(EthApiError::HeaderNotFound(BlockNumberOrTag::Latest.into()))?;
76 let latest_hash = latest.hash();
77
78 if args.base.parent_hash != latest_hash {
79 trace!(flashblock_parent = ?args.base.parent_hash, local_latest=?latest.num_hash(),"Skipping non consecutive flashblock");
80 return Ok(None)
82 }
83
84 let state_provider = self.provider.history_by_block_hash(latest.hash())?;
85
86 let mut request_cache = args
87 .cached_state
88 .take()
89 .filter(|(hash, _)| hash == &latest_hash)
90 .map(|(_, state)| state)
91 .unwrap_or_default();
92 let cached_db = request_cache.as_db_mut(StateProviderDatabase::new(&state_provider));
93 let mut state = State::builder().with_database(cached_db).with_bundle_update().build();
94
95 let mut builder = self
96 .evm_config
97 .builder_for_next_block(&mut state, &latest, args.base.into())
98 .map_err(RethError::other)?;
99
100 builder.apply_pre_execution_changes()?;
101
102 for tx in args.transactions {
103 let _gas_used = builder.execute_transaction(tx)?;
104 }
105
106 let BlockBuilderOutcome { execution_result, block, hashed_state, .. } =
108 if args.compute_state_root {
109 builder.finish(&state_provider)?
110 } else {
111 builder.finish(NoopProvider::default())?
112 };
113
114 let execution_outcome = ExecutionOutcome::new(
115 state.take_bundle(),
116 vec![execution_result.receipts],
117 block.number(),
118 vec![execution_result.requests],
119 );
120
121 let pending_block = PendingBlock::with_executed_block(
122 Instant::now() + Duration::from_secs(1),
123 ExecutedBlock {
124 recovered_block: block.into(),
125 execution_output: Arc::new(execution_outcome),
126 hashed_state: Arc::new(hashed_state),
127 },
128 );
129 let pending_flashblock = PendingFlashBlock::new(
130 pending_block,
131 args.last_flashblock_index,
132 args.last_flashblock_hash,
133 args.compute_state_root,
134 );
135
136 Ok(Some((pending_flashblock, request_cache)))
137 }
138}
139
140impl<EvmConfig: Clone, Provider: Clone> Clone for FlashBlockBuilder<EvmConfig, Provider> {
141 fn clone(&self) -> Self {
142 Self { evm_config: self.evm_config.clone(), provider: self.provider.clone() }
143 }
144}