1pub(crate) use reth_engine_primitives::BigBlockData;
9
10use crate::{
11 evm::{BbBlockExecutorFactory, BbEvmPlan},
12 BigBlockMap,
13};
14use alloy_consensus::Header;
15use alloy_evm::eth::EthBlockExecutionCtx;
16use alloy_primitives::B256;
17use alloy_rpc_types::engine::ExecutionData;
18use core::convert::Infallible;
19use reth_chainspec::{ChainSpec, EthChainSpec};
20use reth_ethereum_forks::Hardforks;
21use reth_ethereum_primitives::EthPrimitives;
22use reth_evm::{
23 ConfigureEngineEvm, ConfigureEvm, Database, EvmEnv, ExecutableTxIterator,
24 NextBlockEnvAttributes,
25};
26use reth_evm_ethereum::{EthBlockAssembler, EthEvmConfig, RethReceiptBuilder};
27use reth_primitives_traits::{SealedBlock, SealedHeader};
28use revm::primitives::hardfork::SpecId;
29use std::sync::Arc;
30use tracing::debug;
31
32use alloy_evm::{eth::spec::EthExecutorSpec, EthEvmFactory};
33use reth_evm::{EvmEnvFor, ExecutionCtxFor};
34
35#[derive(Debug, Clone)]
41pub(crate) struct BigBlockSegment {
42 pub start_tx: usize,
44 pub evm_env: EvmEnv,
46 pub ctx: EthBlockExecutionCtx<'static>,
48}
49
50#[derive(Debug, Clone)]
63pub struct BbEvmConfig<C = ChainSpec> {
64 pub inner: EthEvmConfig<C>,
66 pub pending: BigBlockMap,
68 executor_factory: BbBlockExecutorFactory<Arc<C>>,
70 block_assembler: EthBlockAssembler<C>,
72}
73
74impl<C> BbEvmConfig<C> {
75 pub fn new(inner: EthEvmConfig<C>, pending: BigBlockMap) -> Self
77 where
78 C: Clone,
79 {
80 let chain_spec = inner.chain_spec().clone();
81 let executor_factory = BbBlockExecutorFactory::new(
82 RethReceiptBuilder::default(),
83 chain_spec,
84 EthEvmFactory::default(),
85 );
86 let block_assembler = inner.block_assembler.clone();
87
88 Self { inner, pending, executor_factory, block_assembler }
89 }
90}
91
92fn seed_state_block_hashes<DB>(state: &mut &mut revm::database::State<DB>, hashes: &[(u64, B256)]) {
104 for &(number, hash) in hashes {
105 state.block_hashes.insert(number, hash);
106 }
107}
108
109impl<C> ConfigureEvm for BbEvmConfig<C>
114where
115 C: EthExecutorSpec + EthChainSpec<Header = Header> + Hardforks + 'static,
116{
117 type Primitives = EthPrimitives;
118 type Error = Infallible;
119 type NextBlockEnvCtx = NextBlockEnvAttributes;
120 type BlockExecutorFactory = BbBlockExecutorFactory<Arc<C>>;
121 type BlockAssembler = EthBlockAssembler<C>;
122
123 fn block_executor_factory(&self) -> &Self::BlockExecutorFactory {
124 &self.executor_factory
125 }
126
127 fn block_assembler(&self) -> &Self::BlockAssembler {
128 &self.block_assembler
129 }
130
131 fn evm_env(&self, header: &Header) -> Result<EvmEnv<SpecId>, Self::Error> {
132 self.inner.evm_env(header)
133 }
134
135 fn next_evm_env(
136 &self,
137 parent: &Header,
138 attributes: &NextBlockEnvAttributes,
139 ) -> Result<EvmEnv, Self::Error> {
140 self.inner.next_evm_env(parent, attributes)
141 }
142
143 fn context_for_block<'a>(
144 &self,
145 block: &'a SealedBlock<reth_ethereum_primitives::Block>,
146 ) -> Result<EthBlockExecutionCtx<'a>, Self::Error> {
147 self.inner.context_for_block(block)
148 }
149
150 fn context_for_next_block(
151 &self,
152 parent: &SealedHeader,
153 attributes: Self::NextBlockEnvCtx,
154 ) -> Result<EthBlockExecutionCtx<'_>, Self::Error> {
155 self.inner.context_for_next_block(parent, attributes)
156 }
157
158 fn create_executor<'a, DB, I>(
159 &'a self,
160 evm: reth_evm::EvmFor<Self, &'a mut revm::database::State<DB>, I>,
161 ctx: EthBlockExecutionCtx<'a>,
162 ) -> impl alloy_evm::block::BlockExecutorFor<
163 'a,
164 Self::BlockExecutorFactory,
165 &'a mut revm::database::State<DB>,
166 I,
167 >
168 where
169 DB: Database,
170 I: reth_evm::InspectorFor<Self, &'a mut revm::database::State<DB>> + 'a,
171 {
172 self.executor_factory.create_executor_with_seeder(
178 evm,
179 ctx,
180 Some(seed_state_block_hashes::<DB>),
181 )
182 }
183}
184
185impl<C> ConfigureEngineEvm<ExecutionData> for BbEvmConfig<C>
190where
191 C: EthExecutorSpec + EthChainSpec<Header = Header> + Hardforks + 'static,
192{
193 fn evm_env_for_payload(&self, payload: &ExecutionData) -> Result<EvmEnvFor<Self>, Self::Error> {
194 let payload_hash = payload.block_hash();
195 let has_plan = self.pending.lock().unwrap().contains_key(&payload_hash);
196
197 if has_plan {
198 let first_exec_data = {
201 let pending = self.pending.lock().unwrap();
202 let bb_data = pending.get(&payload_hash).unwrap();
203 bb_data.env_switches[0].1.clone()
204 };
205 let mut env = self.inner.evm_env_for_payload(&first_exec_data)?;
206
207 env.cfg_env.disable_base_fee = true;
211
212 self.stage_plan_for_payload(&payload_hash);
214
215 Ok(env)
216 } else {
217 self.inner.evm_env_for_payload(payload)
218 }
219 }
220
221 fn context_for_payload<'a>(
222 &self,
223 payload: &'a ExecutionData,
224 ) -> Result<ExecutionCtxFor<'a, Self>, Self::Error> {
225 self.inner.context_for_payload(payload)
226 }
227
228 fn tx_iterator_for_payload(
229 &self,
230 payload: &ExecutionData,
231 ) -> Result<impl ExecutableTxIterator<Self>, Self::Error> {
232 self.inner.tx_iterator_for_payload(payload)
233 }
234}
235
236impl<C> BbEvmConfig<C>
241where
242 C: EthExecutorSpec + EthChainSpec<Header = Header> + Hardforks + 'static,
243{
244 pub fn stage_plan_for_payload(&self, payload_hash: &B256) {
251 let bb = match self.pending.lock().unwrap().remove(payload_hash) {
252 Some(bb) => bb,
253 None => return,
254 };
255
256 let segments: Vec<_> = bb
257 .env_switches
258 .into_iter()
259 .map(|(start_tx, exec_data)| {
260 let evm_env = self.inner.evm_env_for_payload(&exec_data).unwrap();
261 let ctx = self.inner.context_for_payload(&exec_data).unwrap();
262 let ctx = EthBlockExecutionCtx {
263 tx_count_hint: ctx.tx_count_hint,
264 parent_hash: ctx.parent_hash,
265 parent_beacon_block_root: ctx.parent_beacon_block_root,
266 ommers: &[],
267 withdrawals: ctx.withdrawals.map(|w| std::borrow::Cow::Owned(w.into_owned())),
268 extra_data: ctx.extra_data,
269 };
270 BigBlockSegment { start_tx, evm_env, ctx }
271 })
272 .collect();
273
274 debug!(
275 target: "engine::bb",
276 ?payload_hash,
277 segments = segments.len(),
278 seed_hashes = bb.prior_block_hashes.len(),
279 "Staging multi-segment plan"
280 );
281
282 let mut plan = BbEvmPlan::new(segments);
283
284 plan.block_hashes_to_seed.extend(bb.prior_block_hashes);
286
287 plan.block_hashes_to_seed.sort_unstable_by_key(|(n, _)| *n);
288
289 self.executor_factory.stage_plan(plan);
290 }
291}