Skip to main content

reth_engine_tree/tree/payload_processor/
reuse.rs

1//! Reuse of speculative prewarm execution results.
2//!
3//! Prewarm workers execute block transactions in parallel against the parent state and record
4//! every account and storage value a transaction reads from the database. When sequential
5//! execution reaches a transaction whose recorded reads still match the current state, it commits
6//! the prewarm result instead of executing the transaction again. Missing or stale results fall
7//! back to normal execution, which never waits for prewarming.
8//!
9//! Most conflicts between transactions are balance changes, such as fee credits to the block
10//! beneficiary or value transfers to popular contracts. A transaction that never observes an
11//! account's balance produces the same result for any balance, apart from the balance itself, so
12//! such balances may differ and the transaction's balance change is applied to the current balance
13//! instead. Balances are observed by `BALANCE`, `SELFBALANCE`, `SELFDESTRUCT` and failed value
14//! transfers. Successful value transfers and gas payments only require enough starting balance
15//! to cover the largest cumulative debit recorded during speculation.
16//!
17//! Prewarming also seeds results of pool transactions that the txpool prewarm worker executed on
18//! top of the parent before the block arrived, see [`PoolSeeds`]. Their block environment is
19//! predicted, so they must not depend on fields that turn out to differ, and their fee credit to
20//! the beneficiary is applied to the actual beneficiary when the result is reused.
21
22use alloy_consensus::InMemorySize;
23use alloy_primitives::{
24    address,
25    map::{B256Map, DefaultHashBuilder, Entry},
26    Address, B256, U256,
27};
28use dashmap::DashMap;
29use parking_lot::{Mutex, RwLock};
30use revm::{
31    bytecode::opcode,
32    context::{
33        result::{HaltReason, InvalidTransaction, ResultAndState},
34        Block, CfgEnv, ContextTr, JournalTr,
35    },
36    inspector::JournalExt,
37    interpreter::{
38        instructions::utility::IntoAddress, interpreter_types::Jumps, CallInputs, CallOutcome,
39        CreateInputs, CreateOutcome, InstructionResult, Interpreter, SuccessOrHalt,
40    },
41    primitives::{StorageKey, StorageValue, KECCAK_EMPTY},
42    state::{Account, AccountInfo, Bytecode, EvmState, EvmStorageSlot},
43    Database, Inspector,
44};
45use std::sync::{
46    atomic::{AtomicUsize, Ordering},
47    Arc,
48};
49
50/// Balances above this are compared exactly, so that applying balance changes cannot overflow.
51const MAX_REBASED_BALANCE: U256 = U256::from_limbs([u64::MAX, u64::MAX, 0, 0]);
52
53/// Beneficiary of speculative pool transaction executions.
54///
55/// Results of transactions that access it are discarded, so its value only affects how many are.
56pub(crate) const POOL_BENEFICIARY: Address = address!("0x00000000000000000000000000000000000beef0");
57
58/// Maximum estimated number of bytes held by [`PoolResults`].
59const MAX_POOL_RESULT_BYTES: usize = 64 << 20;
60
61/// Returns whether blocks executed with `cfg_env` may reuse prewarm results, which excludes
62/// EIP-8037 multidimensional block gas.
63pub(crate) const fn cfg_reuses_prewarm_results<Spec>(cfg_env: &CfgEnv<Spec>) -> bool {
64    !cfg_env.enable_amsterdam_eip8037
65}
66
67/// Speculative prewarm results of a block's transactions, indexed by their position in the block.
68#[derive(Debug)]
69pub(crate) struct PrewarmResults<H> {
70    slots: Box<[Mutex<ResultSlot<H>>]>,
71    /// Writes predicted by the stored results.
72    predicted: Arc<PredictedState>,
73}
74
75/// Prewarm state of a transaction in [`PrewarmResults`].
76#[derive(Debug)]
77enum ResultSlot<H> {
78    /// Prewarming has not executed the transaction.
79    Empty,
80    /// A result that may be reused.
81    Ready(Box<PrewarmedTx<H>>),
82    /// A result that cannot be reused, with the reads it depends on.
83    Unusable(ReadSet),
84    /// Block execution executed the transaction or reused its result, which are published as
85    /// its actual writes.
86    Executed,
87}
88
89impl<H> PrewarmResults<H> {
90    /// Creates empty result slots for `transaction_count` transactions.
91    pub(crate) fn new(transaction_count: usize) -> Self {
92        Self {
93            slots: (0..transaction_count).map(|_| Mutex::new(ResultSlot::Empty)).collect(),
94            predicted: Arc::default(),
95        }
96    }
97
98    /// Returns the writes predicted by the stored results.
99    pub(super) const fn predicted(&self) -> &Arc<PredictedState> {
100        &self.predicted
101    }
102
103    /// Stores the prewarm result of the transaction at `index` and publishes its writes if
104    /// [`ReadSet::finish`] accepts its reads, otherwise marks it as unusable.
105    pub(super) fn store(
106        &self,
107        index: usize,
108        result: ResultAndState<H>,
109        reads: ReadSet,
110        balances: &mut BalanceTracker,
111        tx: SpeculativeTx,
112    ) {
113        match reads.finish(balances, tx) {
114            Ok(reads) => self.set(index, |predicted| {
115                predicted.publish(index, &result.state);
116                ResultSlot::Ready(Box::new(PrewarmedTx { result, reads, credit: None }))
117            }),
118            Err(reads) => self.reject(index, reads),
119        }
120    }
121
122    /// Stores the result of the pool transaction with `hash` as the prewarm result of the
123    /// transaction at `index` and publishes its writes, unless prewarming already executed it or
124    /// the result depends on the block environment fields that `seeds` differ in.
125    ///
126    /// Returns the pool transaction if it was stored.
127    pub(super) fn seed(
128        &self,
129        index: usize,
130        hash: &B256,
131        seeds: &PoolSeeds<H>,
132    ) -> Option<Arc<PoolTx<H>>>
133    where
134        H: Clone,
135    {
136        let tx = seeds.results.get(hash)?;
137        // The speculative execution treated the actual beneficiary as a cold account.
138        if tx.reads.block_env.intersects(seeds.differs) ||
139            tx.reads.position(seeds.beneficiary).is_some()
140        {
141            return None
142        }
143        let mut slot = self.slots.get(index)?.lock();
144        if !matches!(*slot, ResultSlot::Empty) {
145            return None
146        }
147        self.predicted.publish(index, &tx.result.state);
148        *slot = ResultSlot::Ready(Box::new(PrewarmedTx {
149            result: tx.result.clone(),
150            reads: tx.reads.clone(),
151            credit: Some(BeneficiaryCredit { beneficiary: seeds.beneficiary, amount: tx.credit }),
152        }));
153        Some(tx)
154    }
155
156    /// Marks the result of the transaction at `index` as unusable.
157    pub(super) fn reject(&self, index: usize, mut reads: ReadSet) {
158        // Rejection may depend on any balance, such as the caller's.
159        for read in &mut reads.accounts {
160            read.balance = BalanceDependency::Exact;
161        }
162        self.set(index, |_| ResultSlot::Unusable(reads));
163    }
164
165    /// Replaces the predicted writes of the transaction at `index` with the writes of its actual
166    /// execution by block execution.
167    pub(crate) fn publish_executed(&self, index: usize, state: &EvmState) {
168        let Some(slot) = self.slots.get(index) else { return };
169        let mut slot = slot.lock();
170        // Overwrite the predicted writes in place, then retract those the execution did not make.
171        self.predicted.publish(index, state);
172        if let ResultSlot::Ready(previous) = core::mem::replace(&mut *slot, ResultSlot::Executed) {
173            self.predicted.retract_unwritten(index, &previous.result.state, state);
174        }
175        self.predicted.generation.fetch_add(1, Ordering::Relaxed);
176    }
177
178    /// Replaces the slot of the transaction at `index`, retracting the writes of its previous
179    /// result, unless block execution already published its actual writes.
180    fn set(&self, index: usize, f: impl FnOnce(&PredictedState) -> ResultSlot<H>) {
181        let Some(slot) = self.slots.get(index) else { return };
182        let mut slot = slot.lock();
183        match &*slot {
184            ResultSlot::Ready(previous) => self.predicted.retract(index, &previous.result.state),
185            ResultSlot::Executed => return,
186            ResultSlot::Empty | ResultSlot::Unusable(_) => {}
187        }
188        *slot = f(&self.predicted);
189    }
190
191    /// Returns whether the transaction at `index` should be executed again, because prewarming
192    /// skipped it or its reads no longer match the predicted state.
193    pub(super) fn needs_refresh(&self, index: usize) -> bool {
194        let Some(slot) = self.slots.get(index) else { return false };
195        let slot = slot.lock();
196        let reads = match &*slot {
197            ResultSlot::Empty => return true,
198            ResultSlot::Ready(tx) => &tx.reads,
199            ResultSlot::Unusable(reads) => reads,
200            ResultSlot::Executed => return false,
201        };
202        !reads.matches(&self.predicted, index)
203    }
204
205    /// Takes the prewarm result of the transaction at `index` if it is ready and its reads match
206    /// `db`.
207    ///
208    /// The returned result has its balance changes applied to the current balances. Stale results,
209    /// and results whose reads fail, stay in their slot unchanged and are freed with `self`.
210    pub(crate) fn take_valid<DB: Database>(
211        &self,
212        index: usize,
213        db: &mut DB,
214    ) -> Result<Result<ResultAndState<H>, ReuseMiss>, DB::Error> {
215        let Some(slot) = self.slots.get(index) else { return Ok(Err(ReuseMiss::Missing)) };
216        let mut slot = slot.lock();
217        let mut tx = match core::mem::replace(&mut *slot, ResultSlot::Executed) {
218            ResultSlot::Ready(tx) => tx,
219            ResultSlot::Unusable(reads) => {
220                *slot = ResultSlot::Unusable(reads);
221                return Ok(Err(ReuseMiss::Stale))
222            }
223            previous @ (ResultSlot::Empty | ResultSlot::Executed) => {
224                *slot = previous;
225                return Ok(Err(ReuseMiss::Missing))
226            }
227        };
228        let rebased = match tx.validate(db) {
229            Ok(Some(rebased)) => rebased,
230            result => {
231                *slot = ResultSlot::Ready(tx);
232                return result.map(|_| Err(ReuseMiss::Stale))
233            }
234        };
235        // The result stays published as the prediction of this transaction's writes.
236        if rebased {
237            // Later transactions read the rebased balances.
238            self.predicted.publish_accounts(index, &tx.result.state);
239            self.predicted.generation.fetch_add(1, Ordering::Relaxed);
240        }
241        Ok(Ok(tx.result))
242    }
243}
244
245/// Reason a prewarm result could not be reused.
246#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247pub(crate) enum ReuseMiss {
248    /// Prewarming had not finished the transaction.
249    Missing,
250    /// The speculative result was unusable or failed a reuse eligibility check.
251    Stale,
252}
253
254/// A speculative transaction result and the database reads it depends on.
255#[derive(Debug)]
256struct PrewarmedTx<H> {
257    result: ResultAndState<H>,
258    reads: ReadSet,
259    /// The fee credit to apply to the block beneficiary, for results of pool transactions.
260    credit: Option<BeneficiaryCredit>,
261}
262
263/// A fee credit to the block beneficiary that a speculative result does not contain.
264#[derive(Debug)]
265struct BeneficiaryCredit {
266    beneficiary: Address,
267    amount: U256,
268}
269
270impl<H> PrewarmedTx<H> {
271    /// Returns whether all reads match `db`, applying the result's balance changes to the current
272    /// balances of accounts whose balance differs and its credit to the beneficiary, and whether
273    /// any account changed.
274    ///
275    /// The result is left unchanged unless this returns `Some`, so that it can be validated again.
276    fn validate<DB: Database>(&mut self, db: &mut DB) -> Result<Option<bool>, DB::Error> {
277        for read in &self.reads.storage {
278            if db.storage(read.address, read.slot)? != read.value {
279                return Ok(None)
280            }
281        }
282        let mut rebased = Vec::new();
283        for read in &self.reads.accounts {
284            let current = db.basic(read.address)?;
285            match read.compare(current.as_ref()) {
286                AccountMatch::Same => {}
287                AccountMatch::Rebase { speculative, current } => {
288                    if let Some(account) = self.result.state.get(&read.address) {
289                        // All balances are bounded, and the execution never leaves less than the
290                        // difference, so this neither overflows nor underflows.
291                        let Some(balance) = account
292                            .info
293                            .balance
294                            .checked_add(current)
295                            .and_then(|balance| balance.checked_sub(speculative))
296                        else {
297                            return Ok(None)
298                        };
299                        rebased.push(Rebase { address: read.address, balance, original: current });
300                    }
301                }
302                AccountMatch::Differs => return Ok(None),
303            }
304        }
305        let credited = match &self.credit {
306            Some(credit) => {
307                // The beneficiary is not in the result, since the transaction did not read it.
308                // Like execution, load it and touch it even if the credit is zero. A missing
309                // beneficiary would be loaded as not existing, which is not worth supporting.
310                let Some(info) = db.basic(credit.beneficiary)? else { return Ok(None) };
311                let mut account = Account::from(info);
312                // Execution leaves the balance unchanged on overflow.
313                let Some(balance) = account.info.balance.checked_add(credit.amount) else {
314                    return Ok(None)
315                };
316                account.info.balance = balance;
317                account.mark_touch();
318                Some((credit.beneficiary, account))
319            }
320            None => None,
321        };
322        for rebase in &rebased {
323            if let Some(account) = self.result.state.get_mut(&rebase.address) {
324                account.info.balance = rebase.balance;
325                // The state root task only streams accounts whose info differs from the original.
326                account.original_info_mut().balance = rebase.original;
327            }
328        }
329        let changed = !rebased.is_empty() || credited.is_some();
330        self.result.state.extend(credited);
331        Ok(Some(changed))
332    }
333}
334
335/// A balance of a speculative result applied to the current balance.
336#[derive(Debug)]
337struct Rebase {
338    address: Address,
339    /// The balance after the transaction.
340    balance: U256,
341    /// The balance before the transaction.
342    original: U256,
343}
344
345/// How a speculative execution depends on an account's balance.
346#[derive(Debug, Clone, Copy, PartialEq, Eq)]
347enum BalanceDependency {
348    /// The balance was only credited or debited, so it may differ.
349    None,
350    /// The account paid for gas or sent value, so the balance must be at least this large.
351    AtLeast(U256),
352    /// The balance was observed, so it must match.
353    Exact,
354}
355
356/// An account a speculative execution read.
357#[derive(Debug, Clone)]
358struct AccountRead {
359    address: Address,
360    /// The account without its bytecode, `None` if it did not exist.
361    info: Option<AccountInfo>,
362    balance: BalanceDependency,
363    /// Whether the account was read from the predicted state.
364    predicted: bool,
365}
366
367impl AccountRead {
368    /// Compares the read account with `current`.
369    fn compare(&self, current: Option<&AccountInfo>) -> AccountMatch {
370        let (speculative, current) = match (&self.info, current) {
371            (Some(speculative), Some(current)) => (speculative, current),
372            (None, None) => return AccountMatch::Same,
373            _ => return AccountMatch::Differs,
374        };
375        if speculative.balance == current.balance {
376            return if speculative == current { AccountMatch::Same } else { AccountMatch::Differs }
377        }
378
379        let allowed = match self.balance {
380            BalanceDependency::None => true,
381            BalanceDependency::AtLeast(min) => current.balance >= min,
382            BalanceDependency::Exact => false,
383        };
384        // A zero balance can make the account empty, which changes gas costs and EIP-161 state
385        // clearing.
386        if !allowed ||
387            speculative.balance.is_zero() ||
388            current.balance.is_zero() ||
389            current.balance > MAX_REBASED_BALANCE ||
390            (AccountInfo { balance: speculative.balance, ..current.copy_without_code() }) !=
391                *speculative
392        {
393            return AccountMatch::Differs
394        }
395        AccountMatch::Rebase { speculative: speculative.balance, current: current.balance }
396    }
397}
398
399/// How a read account compares with its current state.
400#[derive(Debug, Clone, Copy, PartialEq, Eq)]
401enum AccountMatch {
402    /// The account is unchanged.
403    Same,
404    /// Only the balance changed, so the result's balance change must be applied to the current
405    /// balance.
406    Rebase { speculative: U256, current: U256 },
407    /// The account differs in a way the execution may depend on.
408    Differs,
409}
410
411/// A storage slot a speculative execution read.
412#[derive(Debug, Clone)]
413struct StorageRead {
414    address: Address,
415    slot: StorageKey,
416    value: StorageValue,
417    /// Whether the slot was read from the predicted state.
418    predicted: bool,
419}
420
421/// Database reads of a speculative transaction execution.
422#[derive(Debug, Default, Clone)]
423pub(crate) struct ReadSet {
424    accounts: Vec<AccountRead>,
425    storage: Vec<StorageRead>,
426    /// Whether execution loaded bytecode that is unknown to the database.
427    unknown_code: bool,
428    /// Block environment fields the execution observed.
429    block_env: BlockEnvFields,
430}
431
432impl ReadSet {
433    /// Classifies how the execution depends on the balance of each account it read.
434    ///
435    /// Speculation disables nonce and balance checks, so this fails unless `caller` had the
436    /// transaction's `nonce` and could pay `max_balance_spending`, i.e. unless execution with
437    /// these checks enabled would have accepted the transaction.
438    fn finish(mut self, balances: &mut BalanceTracker, tx: SpeculativeTx) -> Result<Self, Self> {
439        let SpeculativeTx { caller, nonce, max_balance_spending } = tx;
440        // Balance changes are applied once per account.
441        self.accounts.sort_unstable_by_key(|read| read.address);
442        self.accounts.dedup_by_key(|read| read.address);
443        self.block_env = balances.block_env;
444
445        let Ok(caller_index) = self.accounts.binary_search_by_key(&caller, |read| read.address)
446        else {
447            return Err(self)
448        };
449        let caller_info = &self.accounts[caller_index].info;
450        let (caller_nonce, caller_balance) =
451            caller_info.as_ref().map_or((0, U256::ZERO), |info| (info.nonce, info.balance));
452        let Ok(max_balance_spending) = max_balance_spending else { return Err(self) };
453        // Speculation still rejects transactions with the largest nonce, in revm's `validate_env`.
454        if self.unknown_code || caller_nonce != nonce || caller_balance < max_balance_spending {
455            return Err(self)
456        }
457
458        // Rebasing only bounded balances keeps every balance during execution far from overflow,
459        // so no value transfer can overflow in one execution but not the other.
460        let bounded = self
461            .accounts
462            .iter()
463            .all(|read| read.info.as_ref().is_none_or(|info| info.balance <= MAX_REBASED_BALANCE));
464        let paid = caller_balance - max_balance_spending;
465        // Sorted, so that each account is looked up in logarithmic time and the smallest balance
466        // a sender had left comes first.
467        let BalanceTracker { observed, senders, .. } = balances;
468        observed.sort_unstable();
469        senders.sort_unstable();
470        for read in &mut self.accounts {
471            // A sender needs enough balance to leave the same smallest balance, which is the
472            // balance after paying for gas for the caller.
473            let sent = senders
474                .get(senders.partition_point(|(address, _)| *address < read.address))
475                .filter(|(address, _)| *address == read.address)
476                .map(|(_, left)| *left);
477            let left = sent.into_iter().chain((read.address == caller).then_some(paid)).min();
478            read.balance = if !bounded || observed.binary_search(&read.address).is_ok() {
479                BalanceDependency::Exact
480            } else if let Some(left) = left {
481                let balance = read.info.as_ref().map_or(U256::ZERO, |info| info.balance);
482                BalanceDependency::AtLeast(balance.saturating_sub(left))
483            } else {
484                BalanceDependency::None
485            };
486        }
487        Ok(self)
488    }
489
490    /// Returns the position of the read of `address` in the sorted account reads.
491    fn position(&self, address: Address) -> Option<usize> {
492        self.accounts.binary_search_by_key(&address, |read| read.address).ok()
493    }
494
495    /// Returns whether executing the transaction at `index` against `predicted` would read the
496    /// same values, as far as the execution depends on them.
497    fn matches(&self, predicted: &PredictedState, index: usize) -> bool {
498        self.accounts.iter().all(|read| match predicted.account(read.address, index) {
499            Some(account) => read.compare(account.as_ref()) != AccountMatch::Differs,
500            None => !read.predicted,
501        }) && self.storage.iter().all(|read| {
502            match predicted.storage(read.address, read.slot, index) {
503                Some(value) => value == read.value,
504                None => !read.predicted,
505            }
506        })
507    }
508}
509
510/// The fields of a speculatively executed transaction that its validity checks depend on.
511#[derive(Debug)]
512pub(crate) struct SpeculativeTx {
513    /// The transaction's sender.
514    pub(crate) caller: Address,
515    /// The transaction's nonce.
516    pub(crate) nonce: u64,
517    /// The most the caller may spend, or an error if it overflows.
518    pub(crate) max_balance_spending: Result<U256, InvalidTransaction>,
519}
520
521/// Writes of a key, sorted by the index of the transaction that made them.
522type Writes<T> = Vec<(usize, T)>;
523
524/// State writes predicted by speculative results, by transaction index.
525///
526/// Speculative executions read the latest write predicted before their transaction, so that
527/// transactions depending on earlier ones in the block can still be reused.
528#[derive(Debug, Default)]
529pub(super) struct PredictedState {
530    /// Accounts, `None` if destroyed.
531    accounts: DashMap<Address, Writes<Option<AccountInfo>>, DefaultHashBuilder>,
532    storage: DashMap<(Address, StorageKey), Writes<StorageValue>, DefaultHashBuilder>,
533    /// Transactions that cleared an account's storage by creating or destroying it.
534    cleared: DashMap<Address, Writes<()>, DefaultHashBuilder>,
535    /// Bytecode deployed by predicted writes.
536    code: DashMap<B256, Bytecode, DefaultHashBuilder>,
537    /// Number of actual execution or rebased account updates published by block execution.
538    generation: AtomicUsize,
539}
540
541impl PredictedState {
542    /// Returns the number of actual execution or rebased account updates published by block
543    /// execution.
544    pub(super) fn generation(&self) -> usize {
545        self.generation.load(Ordering::Relaxed)
546    }
547
548    /// Returns the latest account write predicted before the transaction at `index`.
549    fn account(&self, address: Address, index: usize) -> Option<Option<AccountInfo>> {
550        let writes = self.accounts.get(&address)?;
551        latest(&writes, index).map(|(_, account)| account.clone())
552    }
553
554    /// Returns the latest storage value predicted before the transaction at `index`.
555    fn storage(&self, address: Address, slot: StorageKey, index: usize) -> Option<StorageValue> {
556        let cleared = self.cleared.get(&address).and_then(|w| latest(&w, index).map(|(i, _)| *i));
557        let written = self.storage.get(&(address, slot)).and_then(|w| latest(&w, index).copied());
558        match (written, cleared) {
559            (Some((written, value)), Some(cleared)) if written >= cleared => Some(value),
560            (_, Some(_)) => Some(StorageValue::ZERO),
561            (written, None) => written.map(|(_, value)| value),
562        }
563    }
564
565    /// Returns predicted bytecode by its hash.
566    fn code(&self, code_hash: B256) -> Option<Bytecode> {
567        self.code.get(&code_hash).map(|code| code.clone())
568    }
569
570    /// Publishes the writes of the transaction at `index`.
571    fn publish(&self, index: usize, state: &EvmState) {
572        self.update(index, state, true);
573        for account in state.values() {
574            if account.is_touched() &&
575                account.is_created() &&
576                let Some(code) = &account.info.code
577            {
578                self.code.insert(account.info.code_hash, code.clone());
579            }
580        }
581    }
582
583    /// Publishes the account writes of the transaction at `index`.
584    fn publish_accounts(&self, index: usize, state: &EvmState) {
585        for (address, account) in state {
586            if account.is_touched() && !account.is_selfdestructed() && !account.info.is_empty() {
587                write(
588                    &mut self.accounts.entry(*address).or_default(),
589                    index,
590                    Some(Some(account.info.copy_without_code())),
591                );
592            }
593        }
594    }
595
596    /// Retracts the writes of the transaction at `index` that were published from `state`.
597    fn retract(&self, index: usize, state: &EvmState) {
598        self.update(index, state, false);
599    }
600
601    /// Retracts the writes of the transaction at `index` that were published from `previous` but
602    /// that `state` does not make.
603    fn retract_unwritten(&self, index: usize, previous: &EvmState, state: &EvmState) {
604        for (address, account) in previous {
605            if !account.is_touched() {
606                continue
607            }
608            let Some(written) = state.get(address).filter(|account| account.is_touched()) else {
609                self.update(index, [(address, account)], false);
610                continue
611            };
612            let clears = |account: &Account| {
613                account.is_selfdestructed() || account.info.is_empty() || account.is_created()
614            };
615            if clears(account) && !clears(written) {
616                write::<()>(&mut self.cleared.entry(*address).or_default(), index, None);
617            }
618            // Storage of destroyed accounts is not published.
619            let destroyed = written.is_selfdestructed() || written.info.is_empty();
620            for (slot, _) in account.changed_storage_slots() {
621                if destroyed || !written.storage.get(slot).is_some_and(|value| value.is_changed()) {
622                    write::<StorageValue>(
623                        &mut self.storage.entry((*address, *slot)).or_default(),
624                        index,
625                        None,
626                    );
627                }
628            }
629        }
630    }
631
632    /// Publishes or retracts the writes of the transaction at `index` to every key that `state`
633    /// writes.
634    fn update<'a>(
635        &self,
636        index: usize,
637        state: impl IntoIterator<Item = (&'a Address, &'a Account)>,
638        publish: bool,
639    ) {
640        for (address, account) in state {
641            if !account.is_touched() {
642                continue
643            }
644            // Touched empty accounts are removed by EIP-161 state clearing.
645            let destroyed = account.is_selfdestructed() || account.info.is_empty();
646            if destroyed || account.is_created() {
647                write(&mut self.cleared.entry(*address).or_default(), index, publish.then_some(()));
648            }
649            // Created bytecode is kept separately, the rest is known to the database.
650            let info = publish.then(|| (!destroyed).then(|| account.info.copy_without_code()));
651            write(&mut self.accounts.entry(*address).or_default(), index, info);
652            if destroyed {
653                continue
654            }
655            for (slot, value) in account.changed_storage_slots() {
656                write(
657                    &mut self.storage.entry((*address, *slot)).or_default(),
658                    index,
659                    publish.then_some(value.present_value),
660                );
661            }
662        }
663    }
664}
665
666/// Sets the write of the transaction at `index`, or removes it if `value` is `None`.
667fn write<T>(writes: &mut Writes<T>, index: usize, value: Option<T>) {
668    match (writes.binary_search_by_key(&index, |(i, _)| *i), value) {
669        (Ok(i), Some(value)) => writes[i].1 = value,
670        (Err(i), Some(value)) => writes.insert(i, (index, value)),
671        (Ok(i), None) => {
672            writes.remove(i);
673        }
674        (Err(_), None) => {}
675    }
676}
677
678/// Returns the latest write before the transaction at `index`.
679fn latest<T>(writes: &[(usize, T)], index: usize) -> Option<&(usize, T)> {
680    writes[..writes.partition_point(|(i, _)| *i < index)].last()
681}
682
683/// Block environment fields that speculative executions may observe and that may differ from the
684/// actual block environment.
685#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
686pub(crate) struct BlockEnvFields {
687    /// The beneficiary, observed by `COINBASE`, by accessing its account, or possibly by running
688    /// out of gas.
689    pub(crate) beneficiary: bool,
690    /// The timestamp, observed by `TIMESTAMP`.
691    pub(crate) timestamp: bool,
692    /// The prevrandao, observed by `PREVRANDAO`.
693    pub(crate) prevrandao: bool,
694    /// The gas limit, observed by `GASLIMIT`.
695    pub(crate) gas_limit: bool,
696}
697
698impl BlockEnvFields {
699    /// Returns whether any field is set in both `self` and `other`.
700    const fn intersects(self, other: Self) -> bool {
701        (self.beneficiary && other.beneficiary) ||
702            (self.timestamp && other.timestamp) ||
703            (self.prevrandao && other.prevrandao) ||
704            (self.gas_limit && other.gas_limit)
705    }
706}
707
708/// Results of pool transactions executed on top of a block's parent in a predicted block
709/// environment with [`POOL_BENEFICIARY`] as the beneficiary, by transaction hash.
710#[derive(Debug)]
711pub(crate) struct PoolResults<H> {
712    stored: RwLock<StoredPoolTxs<H>>,
713}
714
715impl<H> Default for PoolResults<H> {
716    fn default() -> Self {
717        Self { stored: RwLock::new(StoredPoolTxs { txs: B256Map::default(), bytes: 0 }) }
718    }
719}
720
721/// Results of pool transactions stored in [`PoolResults`].
722#[derive(Debug)]
723struct StoredPoolTxs<H> {
724    txs: B256Map<Arc<PoolTx<H>>>,
725    /// Estimated number of bytes held by `txs`.
726    bytes: usize,
727}
728
729impl<H> PoolResults<H> {
730    /// Stores the result of the pool transaction with `hash` if [`ReadSet::finish`] accepts its
731    /// reads, unless it may have accessed the beneficiary, a result is already stored for `hash`,
732    /// or the stored results would hold more than [`MAX_POOL_RESULT_BYTES`].
733    ///
734    /// Returns whether the result was stored.
735    pub(crate) fn store(
736        &self,
737        hash: B256,
738        mut result: ResultAndState<H>,
739        reads: ReadSet,
740        balances: &mut BalanceTracker,
741        tx: SpeculativeTx,
742    ) -> bool {
743        if balances.block_env.beneficiary {
744            return false
745        }
746        let Ok(mut reads) = reads.finish(balances, tx) else { return false };
747
748        // The beneficiary was only loaded to credit fees, which are credited to the actual
749        // beneficiary instead. Crediting fees always loads and touches it, even for zero fees.
750        let Some(beneficiary) = result.state.remove(&POOL_BENEFICIARY) else { return false };
751        let Some(index) = reads.position(POOL_BENEFICIARY) else { return false };
752        let speculative = reads.accounts.remove(index).info.map_or(U256::ZERO, |info| info.balance);
753        // A bounded balance cannot overflow when credited, which would leave it unchanged.
754        if speculative > MAX_REBASED_BALANCE {
755            return false
756        }
757        let Some(credit) = beneficiary.info.balance.checked_sub(speculative) else { return false };
758
759        let bytes = retained_bytes(&result, &reads);
760        let mut stored = self.stored.write();
761        let total = stored.bytes + bytes;
762        if total > MAX_POOL_RESULT_BYTES {
763            return false
764        }
765        let Entry::Vacant(entry) = stored.txs.entry(hash) else { return false };
766        entry.insert(Arc::new(PoolTx { result, reads, credit }));
767        stored.bytes = total;
768        true
769    }
770
771    /// Returns the result of the pool transaction with `hash`.
772    pub(crate) fn get(&self, hash: &B256) -> Option<Arc<PoolTx<H>>> {
773        self.stored.read().txs.get(hash).cloned()
774    }
775
776    /// Returns whether no result is stored.
777    pub(crate) fn is_empty(&self) -> bool {
778        self.stored.read().txs.is_empty()
779    }
780}
781
782/// Returns the estimated number of bytes that storing `result` and `reads` holds.
783fn retained_bytes<H>(result: &ResultAndState<H>, reads: &ReadSet) -> usize {
784    let accounts = result.state.values().map(|account| {
785        // Other bytecode is shared with the database.
786        let code = account.info.code.as_ref().filter(|_| account.is_created());
787        account.storage.capacity() * size_of::<(StorageKey, EvmStorageSlot)>() +
788            code.map_or(0, Bytecode::len)
789    });
790    result.state.capacity() * size_of::<(Address, Account)>() +
791        reads.accounts.capacity() * size_of::<AccountRead>() +
792        reads.storage.capacity() * size_of::<StorageRead>() +
793        result.result.output().map_or(0, |output| output.len()) +
794        result.result.logs().iter().map(InMemorySize::size).sum::<usize>() +
795        accounts.sum::<usize>()
796}
797
798/// A speculative result of a pool transaction without its fee credit to the beneficiary.
799#[derive(Debug)]
800pub(crate) struct PoolTx<H> {
801    result: ResultAndState<H>,
802    reads: ReadSet,
803    /// The fee credit to the beneficiary.
804    credit: U256,
805}
806
807impl<H> PoolTx<H> {
808    /// Returns the state changes of the transaction.
809    pub(super) const fn state(&self) -> &EvmState {
810        &self.result.state
811    }
812
813    /// Loads every read of the transaction from `db`.
814    pub(super) fn load_reads<DB: Database>(&self, db: &mut DB) -> Result<(), DB::Error> {
815        for read in &self.reads.accounts {
816            db.basic(read.address)?;
817        }
818        for read in &self.reads.storage {
819            db.storage(read.address, read.slot)?;
820        }
821        Ok(())
822    }
823}
824
825/// Results of pool transactions that may seed the [`PrewarmResults`] of a block on top of the
826/// parent they were executed on.
827#[derive(Debug, Clone)]
828pub(crate) struct PoolSeeds<H> {
829    results: Arc<PoolResults<H>>,
830    /// The beneficiary of the block.
831    beneficiary: Address,
832    /// Block environment fields that differ from the predicted environment.
833    differs: BlockEnvFields,
834}
835
836impl<H> PoolSeeds<H> {
837    /// Creates seeds for a block with `beneficiary` whose environment differs from the predicted
838    /// environment of `results` in `differs`.
839    pub(crate) const fn new(
840        results: Arc<PoolResults<H>>,
841        beneficiary: Address,
842        differs: BlockEnvFields,
843    ) -> Self {
844        Self { results, beneficiary, differs }
845    }
846}
847
848/// Database wrapper that records reads for [`PrewarmResults`].
849#[derive(Debug)]
850pub(crate) struct RecordingDb<DB> {
851    inner: DB,
852    /// Reads of the current transaction, `None` if recording is disabled.
853    reads: Option<ReadSet>,
854    /// The predicted state, and the index of the current transaction.
855    predicted: Option<(Arc<PredictedState>, usize)>,
856}
857
858impl<DB> RecordingDb<DB> {
859    /// Wraps `inner` without recording.
860    pub(crate) const fn new(inner: DB) -> Self {
861        Self { inner, reads: None, predicted: None }
862    }
863
864    /// Starts recording the reads of the transaction at `index`, which reads `predicted` writes
865    /// of earlier transactions.
866    pub(super) fn start_recording(&mut self, predicted: Arc<PredictedState>, index: usize) {
867        self.reads = Some(ReadSet::default());
868        self.predicted = Some((predicted, index));
869    }
870
871    /// Starts recording the reads of a transaction that only reads the wrapped database.
872    pub(crate) fn start_recording_inner(&mut self) {
873        self.reads = Some(ReadSet::default());
874        self.predicted = None;
875    }
876
877    /// Stops recording and returns the reads of the current transaction.
878    pub(crate) fn take_reads(&mut self) -> Option<ReadSet> {
879        self.predicted = None;
880        self.reads.take()
881    }
882}
883
884impl<DB: Database> Database for RecordingDb<DB> {
885    type Error = DB::Error;
886
887    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
888        let predicted =
889            self.predicted.as_ref().and_then(|(state, index)| state.account(address, *index));
890        let is_predicted = predicted.is_some();
891        let account = match predicted {
892            Some(account) => account,
893            None => self.inner.basic(address)?,
894        };
895
896        if let Some(reads) = &mut self.reads {
897            reads.accounts.push(AccountRead {
898                address,
899                info: account.as_ref().map(AccountInfo::copy_without_code),
900                balance: BalanceDependency::None,
901                predicted: is_predicted,
902            });
903        }
904        Ok(account)
905    }
906
907    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
908        if let Some(code) = self.predicted.as_ref().and_then(|(state, _)| state.code(code_hash)) {
909            return Ok(code)
910        }
911        let code = self.inner.code_by_hash(code_hash)?;
912        // The database returns empty bytecode for unknown hashes.
913        if code.is_empty() &&
914            code_hash != KECCAK_EMPTY &&
915            let Some(reads) = &mut self.reads
916        {
917            reads.unknown_code = true;
918        }
919        Ok(code)
920    }
921
922    fn storage(
923        &mut self,
924        address: Address,
925        index: StorageKey,
926    ) -> Result<StorageValue, Self::Error> {
927        let predicted = self
928            .predicted
929            .as_ref()
930            .and_then(|(state, tx_index)| state.storage(address, index, *tx_index));
931        let is_predicted = predicted.is_some();
932        let value = match predicted {
933            Some(value) => value,
934            None => self.inner.storage(address, index)?,
935        };
936        if let Some(reads) = &mut self.reads {
937            reads.storage.push(StorageRead {
938                address,
939                slot: index,
940                value,
941                predicted: is_predicted,
942            });
943        }
944        Ok(value)
945    }
946
947    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
948        self.inner.block_hash(number)
949    }
950}
951
952/// Inspector that tracks which balances and block environment fields a transaction observes and
953/// which accounts send value.
954#[derive(Debug, Default)]
955pub(crate) struct BalanceTracker {
956    /// Accounts whose balance was observed.
957    observed: Vec<Address>,
958    /// Accounts that sent value, with the balance they had left after each send.
959    senders: Vec<(Address, U256)>,
960    /// Block environment fields that were observed.
961    block_env: BlockEnvFields,
962}
963
964impl BalanceTracker {
965    /// Clears the tracked accounts for a new transaction.
966    pub(crate) fn clear(&mut self) {
967        self.observed.clear();
968        self.senders.clear();
969        self.block_env = BlockEnvFields::default();
970    }
971
972    /// Records whether the transaction may have accessed the beneficiary when a frame ends.
973    ///
974    /// The beneficiary is only loaded after all frames ended to credit fees, unless the
975    /// transaction accessed it. Loaded accounts stay loaded when frames revert. A frame that ran
976    /// out of gas may have skipped loading a cold account, such as an actual beneficiary that is
977    /// warm in the block.
978    fn frame_end<CTX: ContextTr<Journal: JournalExt>>(
979        &mut self,
980        context: &CTX,
981        result: InstructionResult,
982    ) {
983        let out_of_gas = matches!(
984            SuccessOrHalt::<HaltReason>::from(result),
985            SuccessOrHalt::Halt(HaltReason::OutOfGas(_))
986        );
987        let journal = context.journal_ref();
988        self.block_env.beneficiary |= out_of_gas ||
989            (journal.depth() == 0 &&
990                journal.evm_state().contains_key(&context.block().beneficiary()));
991    }
992
993    /// Records that `sender` sends `value`, or observes its balance if it cannot.
994    fn send<CTX: ContextTr<Journal: JournalTr<State = EvmState>>>(
995        &mut self,
996        context: &CTX,
997        sender: Address,
998        value: U256,
999    ) {
1000        // The sender of a frame is always loaded.
1001        let left = context
1002            .journal_ref()
1003            .evm_state()
1004            .get(&sender)
1005            .and_then(|account| account.info.balance.checked_sub(value));
1006        match left {
1007            Some(left) => self.senders.push((sender, left)),
1008            None => self.observed.push(sender),
1009        }
1010    }
1011}
1012
1013impl<CTX: ContextTr<Journal: JournalExt> + ContextTr<Journal: JournalTr<State = EvmState>>>
1014    Inspector<CTX> for BalanceTracker
1015{
1016    fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
1017        let address = match interp.bytecode.opcode() {
1018            opcode::BALANCE => {
1019                let Ok(word) = interp.stack.peek(0) else { return };
1020                word.into_address()
1021            }
1022            opcode::SELFBALANCE | opcode::SELFDESTRUCT => interp.input.target_address,
1023            opcode::COINBASE => {
1024                self.block_env.beneficiary = true;
1025                return
1026            }
1027            opcode::TIMESTAMP => {
1028                self.block_env.timestamp = true;
1029                return
1030            }
1031            opcode::DIFFICULTY => {
1032                self.block_env.prevrandao = true;
1033                return
1034            }
1035            opcode::GASLIMIT => {
1036                self.block_env.gas_limit = true;
1037                return
1038            }
1039            _ => return,
1040        };
1041        // Skip repeated observations, such as in a loop.
1042        if self.observed.last() != Some(&address) {
1043            self.observed.push(address);
1044        }
1045    }
1046
1047    fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
1048        if let Some(value) = inputs.transfer_value().filter(|value| !value.is_zero()) {
1049            self.send(context, inputs.transfer_from(), value);
1050        }
1051        None
1052    }
1053
1054    fn call_end(&mut self, context: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {
1055        if *outcome.instruction_result() == InstructionResult::OutOfFunds {
1056            self.observed.push(inputs.transfer_from());
1057        }
1058        self.frame_end(context, *outcome.instruction_result());
1059    }
1060
1061    fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> {
1062        if !inputs.value().is_zero() {
1063            self.send(context, inputs.caller(), inputs.value());
1064        }
1065        None
1066    }
1067
1068    fn create_end(
1069        &mut self,
1070        context: &mut CTX,
1071        inputs: &CreateInputs,
1072        outcome: &mut CreateOutcome,
1073    ) {
1074        if *outcome.instruction_result() == InstructionResult::OutOfFunds {
1075            self.observed.push(inputs.caller());
1076        }
1077        self.frame_end(context, *outcome.instruction_result());
1078    }
1079}
1080
1081#[cfg(test)]
1082mod tests {
1083    use super::*;
1084    use alloy_consensus::{transaction::Recovered, TxEip1559, TxLegacy};
1085    use alloy_evm::{
1086        block::{BlockExecutor, TxResult},
1087        eth::EthBlockExecutionCtx,
1088        Evm, EvmEnv,
1089    };
1090    use alloy_primitives::{bytes, Bytes, Signature, TxKind};
1091    use reth_errors::ProviderError;
1092    use reth_ethereum_primitives::{Receipt, Transaction, TransactionSigned};
1093    use reth_evm::{ConfigureEvm, EvmFor, HaltReasonFor};
1094    use reth_evm_ethereum::EthEvmConfig;
1095    use revm::{
1096        context::{BlockEnv, CfgEnv, Transaction as _},
1097        database::{states::bundle_state::BundleRetention, BundleState, CacheDB, EmptyDB, State},
1098        primitives::hardfork::SpecId,
1099    };
1100
1101    const BENEFICIARY: Address = Address::repeat_byte(0xbe);
1102    /// Does nothing.
1103    const NOOP: Address = Address::repeat_byte(0xc0);
1104    /// Increments slot 0.
1105    const COUNTER: Address = Address::repeat_byte(0xc1);
1106    /// Stores the beneficiary balance in slot 0.
1107    const BENEFICIARY_BALANCE_READER: Address = Address::repeat_byte(0xc2);
1108    /// Stores its own balance in slot 0.
1109    const SELF_BALANCE_READER: Address = Address::repeat_byte(0xc3);
1110    /// Sends 5 wei to [`NOOP`].
1111    const FORWARDER: Address = Address::repeat_byte(0xc4);
1112    /// Has a balance above [`MAX_REBASED_BALANCE`].
1113    const RICH: Address = Address::repeat_byte(0xc5);
1114    /// Exists with a zero balance.
1115    const ZERO_BALANCE: Address = Address::repeat_byte(0xc6);
1116    /// Has a code hash whose bytecode the database does not know.
1117    const UNKNOWN_CODE: Address = Address::repeat_byte(0xc7);
1118    /// Stores the timestamp in slot 0.
1119    const TIMESTAMP_READER: Address = Address::repeat_byte(0xc8);
1120    /// Stores the gas limit in slot 0.
1121    const GAS_LIMIT_READER: Address = Address::repeat_byte(0xc9);
1122    /// Stores the beneficiary in slot 0.
1123    const BENEFICIARY_READER: Address = Address::repeat_byte(0xca);
1124    /// Calls [`POOL_BENEFICIARY`].
1125    const POOL_BENEFICIARY_CALLER: Address = Address::repeat_byte(0xcb);
1126    /// Reads the balance of [`BENEFICIARY`] by its address.
1127    const BENEFICIARY_BALANCE_BY_ADDRESS: Address = Address::repeat_byte(0xcc);
1128    /// Stores the prevrandao in slot 0.
1129    const PREVRANDAO_READER: Address = Address::repeat_byte(0xcd);
1130    /// Has the largest balance.
1131    const SATURATED: Address = Address::repeat_byte(0xce);
1132    /// Index of a sender with the largest nonce.
1133    const EXHAUSTED_SENDER: u8 = 5;
1134    const GAS_PRICE: u128 = 2;
1135
1136    type Results = PrewarmResults<HaltReasonFor<EthEvmConfig>>;
1137
1138    fn evm_env(prewarm: bool) -> EvmEnv {
1139        let mut cfg_env = CfgEnv::new_with_spec(SpecId::CANCUN).with_chain_id(1);
1140        cfg_env.disable_nonce_check = prewarm;
1141        cfg_env.disable_balance_check = prewarm;
1142        let block_env = BlockEnv {
1143            number: U256::from(1),
1144            beneficiary: BENEFICIARY,
1145            basefee: 1,
1146            gas_limit: 30_000_000,
1147            ..Default::default()
1148        };
1149        EvmEnv { cfg_env, block_env }
1150    }
1151
1152    fn sender(i: u8) -> Address {
1153        Address::repeat_byte(i)
1154    }
1155
1156    fn tx(from: u8, nonce: u64, to: Address, value: u64) -> Recovered<TransactionSigned> {
1157        tx_with_gas_limit(from, nonce, to, value, 100_000)
1158    }
1159
1160    fn tx_with_gas_limit(
1161        from: u8,
1162        nonce: u64,
1163        to: Address,
1164        value: u64,
1165        gas_limit: u64,
1166    ) -> Recovered<TransactionSigned> {
1167        let tx = Transaction::Legacy(TxLegacy {
1168            chain_id: Some(1),
1169            nonce,
1170            gas_price: GAS_PRICE,
1171            gas_limit,
1172            to: TxKind::Call(to),
1173            value: U256::from(value),
1174            input: Bytes::new(),
1175        });
1176        Recovered::new_unchecked(
1177            TransactionSigned::new_unhashed(tx, Signature::test_signature()),
1178            sender(from),
1179        )
1180    }
1181
1182    fn parent_state() -> CacheDB<EmptyDB> {
1183        let mut db = CacheDB::new(EmptyDB::default());
1184        // The exhausted sender is funded separately.
1185        for i in [1, 2, 3, 4, 6, 7] {
1186            db.insert_account_info(
1187                sender(i),
1188                AccountInfo { balance: U256::from(10u64.pow(18)), ..Default::default() },
1189            );
1190        }
1191        db.insert_account_info(
1192            sender(EXHAUSTED_SENDER),
1193            AccountInfo {
1194                balance: U256::from(10u64.pow(18)),
1195                nonce: u64::MAX,
1196                ..Default::default()
1197            },
1198        );
1199        db.insert_account_info(
1200            BENEFICIARY,
1201            AccountInfo { balance: U256::from(1), ..Default::default() },
1202        );
1203        db.insert_account_info(RICH, AccountInfo { balance: U256::MAX >> 1, ..Default::default() });
1204        db.insert_account_info(SATURATED, AccountInfo { balance: U256::MAX, ..Default::default() });
1205        db.insert_account_info(ZERO_BALANCE, AccountInfo { nonce: 1, ..Default::default() });
1206        db.insert_account_info(
1207            UNKNOWN_CODE,
1208            AccountInfo { code_hash: B256::repeat_byte(0xab), code: None, ..Default::default() },
1209        );
1210        for (address, code) in [
1211            (NOOP, bytes!("00")),
1212            (COUNTER, bytes!("5f546001015f5500")),
1213            (BENEFICIARY_BALANCE_READER, bytes!("41315f5500")),
1214            (SELF_BALANCE_READER, bytes!("475f5500")),
1215            (FORWARDER, bytes!("5f5f5f5f600573c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c05af100")),
1216            (TIMESTAMP_READER, bytes!("425f5500")),
1217            (GAS_LIMIT_READER, bytes!("455f5500")),
1218            (BENEFICIARY_READER, bytes!("415f5500")),
1219            (
1220                POOL_BENEFICIARY_CALLER,
1221                bytes!("5f5f5f5f5f7300000000000000000000000000000000000beef05af100"),
1222            ),
1223            (
1224                BENEFICIARY_BALANCE_BY_ADDRESS,
1225                bytes!("73bebebebebebebebebebebebebebebebebebebebe3100"),
1226            ),
1227            (PREVRANDAO_READER, bytes!("445f5500")),
1228        ] {
1229            let code = Bytecode::new_raw(code);
1230            db.insert_account_info(
1231                address,
1232                AccountInfo {
1233                    balance: U256::from(12),
1234                    code_hash: code.hash_slow(),
1235                    code: Some(code),
1236                    ..Default::default()
1237                },
1238            );
1239        }
1240        db
1241    }
1242
1243    /// Speculative execution of `txs`, as by prewarm workers.
1244    struct Prewarm<'a> {
1245        txs: &'a [Recovered<TransactionSigned>],
1246        results: Results,
1247        evm: EvmFor<EthEvmConfig, RecordingDb<CacheDB<EmptyDB>>, BalanceTracker>,
1248    }
1249
1250    impl<'a> Prewarm<'a> {
1251        /// Executes the transactions at the indices in `order`, then refreshes stale results
1252        /// among them in block order.
1253        fn new(txs: &'a [Recovered<TransactionSigned>], order: &[usize]) -> Self {
1254            let evm = EthEvmConfig::mainnet().evm_with_env_and_inspector(
1255                RecordingDb::new(parent_state()),
1256                evm_env(true),
1257                BalanceTracker::default(),
1258            );
1259            let mut prewarm = Self { txs, results: Results::new(txs.len()), evm };
1260            for &index in order {
1261                prewarm.run(index);
1262            }
1263            let mut refresh = order.to_vec();
1264            refresh.sort_unstable();
1265            for index in refresh {
1266                if prewarm.results.needs_refresh(index) {
1267                    prewarm.run(index);
1268                }
1269            }
1270            prewarm
1271        }
1272
1273        fn run(&mut self, index: usize) {
1274            let tx = &self.txs[index];
1275            let tx_env = EthEvmConfig::mainnet().tx_env(tx);
1276            let speculative = SpeculativeTx {
1277                caller: tx.signer(),
1278                nonce: tx_env.nonce,
1279                max_balance_spending: tx_env.max_balance_spending(),
1280            };
1281            self.evm.db_mut().start_recording(Arc::clone(self.results.predicted()), index);
1282            self.evm.inspector_mut().clear();
1283            let result = self.evm.transact(tx_env);
1284            let reads = self.evm.db_mut().take_reads().unwrap();
1285            match result {
1286                Ok(result) => {
1287                    self.results.store(index, result, reads, self.evm.inspector_mut(), speculative)
1288                }
1289                Err(_) => self.results.reject(index, reads),
1290            }
1291        }
1292
1293        /// Refreshes stale or missing results of transactions after `index`.
1294        fn refresh_after(&mut self, index: usize) {
1295            for index in index + 1..self.txs.len() {
1296                if self.results.needs_refresh(index) {
1297                    self.run(index);
1298                }
1299            }
1300        }
1301    }
1302
1303    /// Executes `txs` sequentially, committing valid prewarm results instead of executing.
1304    ///
1305    /// If `publish` is set, prewarm results are refreshed against the writes of executed
1306    /// transactions.
1307    fn execute(
1308        txs: &[Recovered<TransactionSigned>],
1309        mut prewarm: Option<&mut Prewarm<'_>>,
1310        publish: bool,
1311        beneficiary: Address,
1312    ) -> Execution {
1313        let config = EthEvmConfig::mainnet();
1314        let mut state = State::builder().with_database(parent_state()).with_bundle_update().build();
1315        let mut evm_env = evm_env(false);
1316        evm_env.block_env.beneficiary = beneficiary;
1317        let evm = config.evm_with_env(&mut state, evm_env);
1318        let ctx = EthBlockExecutionCtx {
1319            parent_hash: B256::ZERO,
1320            parent_beacon_block_root: None,
1321            ommers: &[],
1322            withdrawals: None,
1323            extra_data: Bytes::new(),
1324            tx_count_hint: None,
1325            slot_number: None,
1326        };
1327        let mut executor = config.create_executor(evm, ctx);
1328        let mut outcomes = Vec::new();
1329        let mut changes = Vec::new();
1330        for (index, tx) in txs.iter().enumerate() {
1331            let Some(prewarm) = prewarm.as_deref_mut() else {
1332                executor
1333                    .execute_transaction_with_result_closure(tx, |result| {
1334                        changes.push(changed_accounts(&result.result().state))
1335                    })
1336                    .unwrap();
1337                outcomes.push(Err(ReuseMiss::Missing));
1338                continue
1339            };
1340            let outcome =
1341                match prewarm.results.take_valid(index, executor.evm_mut().db_mut()).unwrap() {
1342                    Ok(result) => {
1343                        changes.push(changed_accounts(&result.state));
1344                        executor.commit_transaction(
1345                            config.prewarm_tx_result(tx.inner(), result).unwrap(),
1346                        );
1347                        Ok(())
1348                    }
1349                    Err(miss) => {
1350                        executor
1351                            .execute_transaction_with_result_closure(tx, |result| {
1352                                changes.push(changed_accounts(&result.result().state));
1353                                if publish {
1354                                    prewarm.results.publish_executed(index, &result.result().state)
1355                                }
1356                            })
1357                            .unwrap();
1358                        if publish {
1359                            prewarm.refresh_after(index);
1360                        }
1361                        Err(miss)
1362                    }
1363                };
1364            outcomes.push(outcome);
1365        }
1366        let receipts = executor.receipts().to_vec();
1367        drop(executor);
1368        state.merge_transitions(BundleRetention::Reverts);
1369        Execution { receipts, bundle: state.take_bundle(), changes, outcomes }
1370    }
1371
1372    /// Output of [`execute`].
1373    struct Execution {
1374        receipts: Vec<Receipt>,
1375        bundle: BundleState,
1376        /// Accounts each transaction changed, as the state root task sees them.
1377        changes: Vec<Vec<(Address, AccountInfo)>>,
1378        outcomes: Vec<Result<(), ReuseMiss>>,
1379    }
1380
1381    /// Returns the accounts in `state` whose info differs from their original info, which the
1382    /// state root task streams as updates.
1383    fn changed_accounts(state: &EvmState) -> Vec<(Address, AccountInfo)> {
1384        let mut changed = state
1385            .iter()
1386            .filter(|(_, account)| account.is_touched() && account.info != account.original_info())
1387            .map(|(address, account)| (*address, account.info.copy_without_code()))
1388            .collect::<Vec<_>>();
1389        changed.sort_unstable_by_key(|(address, _)| *address);
1390        changed
1391    }
1392
1393    /// Database that fails every read.
1394    struct FailingDb;
1395
1396    impl Database for FailingDb {
1397        type Error = ProviderError;
1398
1399        fn basic(&mut self, _address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1400            Err(ProviderError::BestBlockNotFound)
1401        }
1402
1403        fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
1404            Err(ProviderError::BestBlockNotFound)
1405        }
1406
1407        fn storage(
1408            &mut self,
1409            _address: Address,
1410            _index: StorageKey,
1411        ) -> Result<StorageValue, Self::Error> {
1412            Err(ProviderError::BestBlockNotFound)
1413        }
1414
1415        fn block_hash(&mut self, _number: u64) -> Result<B256, Self::Error> {
1416            Err(ProviderError::BestBlockNotFound)
1417        }
1418    }
1419
1420    /// Returns whether the prewarm result of the first transaction can be reused, for
1421    /// transactions that block execution would reject.
1422    fn reusable(txs: &[Recovered<TransactionSigned>]) -> Result<(), ReuseMiss> {
1423        let prewarm = Prewarm::new(txs, &[0]);
1424        let mut state = State::builder().with_database(parent_state()).build();
1425        prewarm.results.take_valid(0, &mut state).unwrap().map(drop)
1426    }
1427
1428    /// Asserts that reusing prewarm results produces the same output as executing every
1429    /// transaction, and returns the reuse outcomes.
1430    fn reuse(txs: &[Recovered<TransactionSigned>]) -> Vec<Result<(), ReuseMiss>> {
1431        reuse_in(txs, &(0..txs.len()).collect::<Vec<_>>(), true)
1432    }
1433
1434    /// Like [`reuse`], prewarming only the transactions at the indices in `order`, and refreshing
1435    /// results against the writes of executed transactions if `publish` is set.
1436    fn reuse_in(
1437        txs: &[Recovered<TransactionSigned>],
1438        order: &[usize],
1439        publish: bool,
1440    ) -> Vec<Result<(), ReuseMiss>> {
1441        let reused = execute(txs, Some(&mut Prewarm::new(txs, order)), publish, BENEFICIARY);
1442        let expected = execute(txs, None, false, BENEFICIARY);
1443        assert_eq!(reused.receipts, expected.receipts);
1444        assert_eq!(reused.bundle, expected.bundle);
1445        assert_eq!(reused.changes, expected.changes);
1446        reused.outcomes
1447    }
1448
1449    /// Executes `txs` as pool transactions on top of the parent state, as by the txpool prewarm
1450    /// worker, in a block environment that differs from the actual one in the timestamp and
1451    /// prevrandao.
1452    fn pool_results(
1453        txs: &[Recovered<TransactionSigned>],
1454    ) -> PoolResults<HaltReasonFor<EthEvmConfig>> {
1455        let mut evm_env = evm_env(true);
1456        evm_env.block_env.beneficiary = POOL_BENEFICIARY;
1457        evm_env.block_env.timestamp = U256::from(12);
1458        evm_env.block_env.prevrandao = Some(B256::repeat_byte(1));
1459        let mut evm = EthEvmConfig::mainnet().evm_with_env_and_inspector(
1460            RecordingDb::new(parent_state()),
1461            evm_env,
1462            BalanceTracker::default(),
1463        );
1464        let results = PoolResults::default();
1465        for tx in txs {
1466            let tx_env = EthEvmConfig::mainnet().tx_env(tx);
1467            let speculative = SpeculativeTx {
1468                caller: tx.signer(),
1469                nonce: tx_env.nonce,
1470                max_balance_spending: tx_env.max_balance_spending(),
1471            };
1472            evm.db_mut().start_recording_inner();
1473            evm.inspector_mut().clear();
1474            let result = evm.transact(tx_env).unwrap();
1475            let reads = evm.db_mut().take_reads().unwrap();
1476            results.store(*tx.tx_hash(), result, reads, evm.inspector_mut(), speculative);
1477        }
1478        results
1479    }
1480
1481    /// Asserts that reusing results of the `pool` transactions produces the same output as
1482    /// executing every transaction in a block with `beneficiary`, and returns the reuse outcomes.
1483    fn reuse_pool(
1484        txs: &[Recovered<TransactionSigned>],
1485        pool: &[Recovered<TransactionSigned>],
1486        beneficiary: Address,
1487    ) -> Vec<Result<(), ReuseMiss>> {
1488        let differs = BlockEnvFields { timestamp: true, prevrandao: true, ..Default::default() };
1489        reuse_pool_with(txs, pool, beneficiary, differs)
1490    }
1491
1492    /// Like [`reuse_pool`], for a block environment that differs from the predicted one in
1493    /// `differs`.
1494    fn reuse_pool_with(
1495        txs: &[Recovered<TransactionSigned>],
1496        pool: &[Recovered<TransactionSigned>],
1497        beneficiary: Address,
1498        differs: BlockEnvFields,
1499    ) -> Vec<Result<(), ReuseMiss>> {
1500        let seeds = PoolSeeds::new(Arc::new(pool_results(pool)), beneficiary, differs);
1501        let mut prewarm = Prewarm::new(txs, &[]);
1502        for (index, tx) in txs.iter().enumerate() {
1503            prewarm.results.seed(index, tx.tx_hash(), &seeds);
1504        }
1505        let reused = execute(txs, Some(&mut prewarm), false, beneficiary);
1506        let expected = execute(txs, None, false, beneficiary);
1507        assert_eq!(reused.receipts, expected.receipts);
1508        assert_eq!(reused.bundle, expected.bundle);
1509        assert_eq!(reused.changes, expected.changes);
1510        reused.outcomes
1511    }
1512
1513    #[test]
1514    fn reuses_independent_transactions() {
1515        let txs = [tx(1, 0, sender(2), 1), tx(3, 0, Address::repeat_byte(0xaa), 1)];
1516        assert_eq!(reuse(&txs), [Ok(()), Ok(())]);
1517    }
1518
1519    #[test]
1520    fn rebases_unobserved_balances() {
1521        // The last transaction's caller and recipient were credited by earlier ones.
1522        let txs = [tx(1, 0, NOOP, 1), tx(1, 1, sender(2), 1), tx(2, 0, NOOP, 1)];
1523        assert_eq!(reuse(&txs), [Ok(()), Ok(()), Ok(())]);
1524    }
1525
1526    #[test]
1527    fn reuses_predicted_writes() {
1528        let txs = [tx(1, 0, COUNTER, 1), tx(2, 0, COUNTER, 1), tx(1, 1, COUNTER, 1)];
1529        assert_eq!(reuse(&txs), [Ok(()), Ok(()), Ok(())]);
1530        // Results executed before the transactions they depend on are executed again.
1531        assert_eq!(reuse_in(&txs, &[2, 1, 0], true), [Ok(()), Ok(()), Ok(())]);
1532    }
1533
1534    #[test]
1535    fn refreshes_against_executed_writes() {
1536        let txs = [tx(1, 0, COUNTER, 1), tx(2, 0, COUNTER, 1), tx(1, 1, sender(3), 1)];
1537        assert_eq!(reuse_in(&txs, &[1, 2], true), [Err(ReuseMiss::Missing), Ok(()), Ok(())]);
1538    }
1539
1540    #[test]
1541    fn rebases_original_balances() {
1542        // The first transaction leaves the forwarder 5 wei more, and the second forwards 5 wei, so
1543        // its rebased balance equals its speculative balance before the second transaction.
1544        let txs = [tx(1, 0, FORWARDER, 10), tx(2, 0, FORWARDER, 0)];
1545        assert_eq!(reuse_in(&txs, &[1], false), [Err(ReuseMiss::Missing), Ok(())]);
1546    }
1547
1548    #[test]
1549    fn rejects_stale_storage() {
1550        let txs = [tx(1, 0, COUNTER, 1), tx(2, 0, COUNTER, 1)];
1551        assert_eq!(reuse_in(&txs, &[1], false), [Err(ReuseMiss::Missing), Err(ReuseMiss::Stale)]);
1552    }
1553
1554    #[test]
1555    fn rejects_stale_callers() {
1556        let txs = [tx(1, 0, sender(2), 1), tx(1, 1, sender(3), 1)];
1557        assert_eq!(reuse_in(&txs, &[1], false), [Err(ReuseMiss::Missing), Err(ReuseMiss::Stale)]);
1558    }
1559
1560    #[test]
1561    fn rejects_observed_balances() {
1562        let txs = [
1563            tx(1, 0, SELF_BALANCE_READER, 1),
1564            tx(2, 0, SELF_BALANCE_READER, 1),
1565            tx(3, 0, BENEFICIARY_BALANCE_READER, 1),
1566        ];
1567        assert_eq!(
1568            reuse_in(&txs, &[1, 2], false),
1569            [Err(ReuseMiss::Missing), Err(ReuseMiss::Stale), Err(ReuseMiss::Stale)]
1570        );
1571    }
1572
1573    #[test]
1574    fn rejects_lower_sender_balances() {
1575        let txs = [tx(1, 0, FORWARDER, 0), tx(2, 0, FORWARDER, 0), tx(3, 0, FORWARDER, 0)];
1576        // The forwarder can send twice from its speculative balance, but not three times.
1577        assert_eq!(
1578            reuse_in(&txs, &[1, 2], false),
1579            [Err(ReuseMiss::Missing), Ok(()), Err(ReuseMiss::Stale)]
1580        );
1581    }
1582
1583    #[test]
1584    fn reuses_pool_results() {
1585        // The last transaction's caller was credited by the first one.
1586        let txs = [tx(1, 0, sender(2), 1), tx(3, 0, COUNTER, 1), tx(2, 0, GAS_LIMIT_READER, 1)];
1587        assert_eq!(reuse_pool(&txs, &txs, BENEFICIARY), [Ok(()), Ok(()), Ok(())]);
1588        // Transactions missing from the pool are executed.
1589        assert_eq!(
1590            reuse_pool(&txs, &txs[1..], BENEFICIARY),
1591            [Err(ReuseMiss::Missing), Ok(()), Ok(())]
1592        );
1593    }
1594
1595    #[test]
1596    fn rejects_stale_pool_results() {
1597        // Test transactions are hashed without their sender.
1598        let txs = [tx(1, 0, COUNTER, 1), tx(2, 0, COUNTER, 2)];
1599        assert_eq!(reuse_pool(&txs, &txs, BENEFICIARY), [Ok(()), Err(ReuseMiss::Stale)]);
1600        // The beneficiary must exist to be credited.
1601        let missing = Address::repeat_byte(0xbf);
1602        assert_eq!(reuse_pool(&txs, &txs, missing), [Err(ReuseMiss::Stale), Err(ReuseMiss::Stale)]);
1603    }
1604
1605    #[test]
1606    fn rejects_pool_results_observing_block_env() {
1607        let txs = [
1608            tx(1, 0, TIMESTAMP_READER, 1),
1609            tx(2, 0, BENEFICIARY_READER, 1),
1610            tx(3, 0, POOL_BENEFICIARY, 1),
1611            tx(4, 0, POOL_BENEFICIARY_CALLER, 1),
1612            tx(6, 0, BENEFICIARY, 1),
1613            tx(7, 0, PREVRANDAO_READER, 1),
1614        ];
1615        assert_eq!(reuse_pool(&txs, &txs, BENEFICIARY), [Err(ReuseMiss::Missing); 6]);
1616
1617        let txs = [tx(1, 0, GAS_LIMIT_READER, 1)];
1618        let differs = BlockEnvFields { gas_limit: true, ..Default::default() };
1619        assert_eq!(reuse_pool_with(&txs, &txs, BENEFICIARY, differs), [Err(ReuseMiss::Missing)]);
1620    }
1621
1622    #[test]
1623    fn seeds_only_unexecuted_transactions() {
1624        let txs = [tx(1, 0, COUNTER, 1)];
1625        let differs = BlockEnvFields::default();
1626        let seeds = PoolSeeds::new(Arc::new(pool_results(&txs)), BENEFICIARY, differs);
1627        assert!(Prewarm::new(&txs, &[]).results.seed(0, txs[0].tx_hash(), &seeds).is_some());
1628        assert!(Prewarm::new(&txs, &[0]).results.seed(0, txs[0].tx_hash(), &seeds).is_none());
1629    }
1630
1631    #[test]
1632    fn rejects_pool_results_overflowing_the_beneficiary() {
1633        let txs = [tx(1, 0, COUNTER, 1)];
1634        assert_eq!(reuse_pool(&txs, &txs, SATURATED), [Err(ReuseMiss::Stale)]);
1635    }
1636
1637    /// Stores the recorded result of `tx` in `results` again under `hash`, after `modify` changed
1638    /// it and the read of the pool beneficiary.
1639    fn store_again(
1640        results: &PoolResults<HaltReasonFor<EthEvmConfig>>,
1641        tx: &Recovered<TransactionSigned>,
1642        hash: B256,
1643        modify: impl FnOnce(&mut ResultAndState<HaltReasonFor<EthEvmConfig>>, &mut AccountRead),
1644    ) -> bool {
1645        let recorded = results.get(tx.tx_hash()).unwrap();
1646        let mut result = recorded.result.clone();
1647        result.state.insert(POOL_BENEFICIARY, Account::default());
1648        let mut beneficiary = AccountRead {
1649            address: POOL_BENEFICIARY,
1650            info: None,
1651            balance: BalanceDependency::None,
1652            predicted: false,
1653        };
1654        modify(&mut result, &mut beneficiary);
1655        let mut reads = recorded.reads.clone();
1656        reads.accounts.push(beneficiary);
1657        let tx_env = EthEvmConfig::mainnet().tx_env(tx);
1658        let speculative = SpeculativeTx {
1659            caller: tx.signer(),
1660            nonce: tx_env.nonce,
1661            max_balance_spending: tx_env.max_balance_spending(),
1662        };
1663        results.store(hash, result, reads, &mut BalanceTracker::default(), speculative)
1664    }
1665
1666    #[test]
1667    fn bounds_pool_results() {
1668        let txs = [tx(1, 0, COUNTER, 1)];
1669        let results = pool_results(&txs);
1670        assert!(store_again(&results, &txs[0], B256::ZERO, |_, _| {}));
1671        // Deployed code counts towards the bound.
1672        assert!(!store_again(&results, &txs[0], B256::with_last_byte(1), |result, _| {
1673            let account = result.state.get_mut(&COUNTER).unwrap();
1674            account.mark_created();
1675            account.info.code = Some(Bytecode::new_raw(vec![0; MAX_POOL_RESULT_BYTES].into()));
1676        }));
1677    }
1678
1679    #[test]
1680    fn rejects_recorded_pool_hashes() {
1681        let txs = [tx(1, 0, COUNTER, 1)];
1682        let results = pool_results(&txs);
1683        assert!(!store_again(&results, &txs[0], *txs[0].tx_hash(), |_, _| {}));
1684        assert!(store_again(&results, &txs[0], B256::ZERO, |_, _| {}));
1685    }
1686
1687    #[test]
1688    fn rejects_saturated_pool_beneficiaries() {
1689        let txs = [tx(1, 0, COUNTER, 1)];
1690        let results = pool_results(&txs);
1691        // Crediting a saturated balance leaves it unchanged.
1692        assert!(!store_again(&results, &txs[0], B256::ZERO, |result, beneficiary| {
1693            beneficiary.info = Some(AccountInfo { balance: U256::MAX, ..Default::default() });
1694            result.state.get_mut(&POOL_BENEFICIARY).unwrap().info.balance = U256::MAX;
1695        }));
1696        assert!(store_again(&results, &txs[0], B256::ZERO, |_, _| {}));
1697    }
1698
1699    #[test]
1700    fn rejects_pool_results_running_out_of_gas() {
1701        // Enough gas to read the balance of the warm beneficiary in the block, but not of the cold
1702        // one during speculation.
1703        let txs = [tx_with_gas_limit(1, 0, BENEFICIARY_BALANCE_BY_ADDRESS, 0, 21_500)];
1704        assert_eq!(reuse_pool(&txs, &txs, BENEFICIARY), [Err(ReuseMiss::Missing)]);
1705    }
1706
1707    #[test]
1708    fn rejects_invalid_transactions() {
1709        assert_eq!(reusable(&[tx(1, 0, NOOP, 0)]), Ok(()));
1710        // The caller cannot pay for the value.
1711        assert_eq!(reusable(&[tx(1, 0, NOOP, 10u64.pow(19))]), Err(ReuseMiss::Stale));
1712        // The caller's nonce differs.
1713        assert_eq!(reusable(&[tx(1, 1, NOOP, 0)]), Err(ReuseMiss::Stale));
1714        // The caller's nonce cannot be incremented.
1715        assert_eq!(reusable(&[tx(EXHAUSTED_SENDER, u64::MAX, NOOP, 0)]), Err(ReuseMiss::Stale));
1716        // Speculative execution fails.
1717        assert_eq!(
1718            reusable(&[tx_with_gas_limit(1, 0, NOOP, 0, 40_000_000)]),
1719            Err(ReuseMiss::Stale)
1720        );
1721        // The most the caller may spend overflows, though the effective fee does not.
1722        let overflowing = Transaction::Eip1559(TxEip1559 {
1723            chain_id: 1,
1724            max_fee_per_gas: u128::MAX,
1725            gas_limit: 100_000,
1726            to: TxKind::Call(NOOP),
1727            ..Default::default()
1728        });
1729        let overflowing = Recovered::new_unchecked(
1730            TransactionSigned::new_unhashed(overflowing, Signature::test_signature()),
1731            sender(1),
1732        );
1733        assert_eq!(reusable(&[overflowing]), Err(ReuseMiss::Stale));
1734    }
1735
1736    #[test]
1737    fn keeps_stale_results_unchanged() {
1738        let txs = [tx(1, 0, NOOP, 0)];
1739        let prewarm = Prewarm::new(&txs, &[0]);
1740        // The caller's balance can be rebased, but the callee changed.
1741        let mut db = parent_state();
1742        db.insert_account_info(
1743            sender(1),
1744            AccountInfo { balance: U256::from(2 * 10u64.pow(18)), ..Default::default() },
1745        );
1746        let mut noop = db.basic(NOOP).unwrap().unwrap();
1747        noop.nonce = 1;
1748        db.insert_account_info(NOOP, noop);
1749        let mut stale = State::builder().with_database(db).build();
1750        assert_eq!(
1751            prewarm.results.take_valid(0, &mut stale).unwrap().map(drop),
1752            Err(ReuseMiss::Stale)
1753        );
1754
1755        let mut state = State::builder().with_database(parent_state()).build();
1756        let result = prewarm.results.take_valid(0, &mut state).unwrap().unwrap();
1757        let fee = U256::from(21_000 * GAS_PRICE);
1758        assert_eq!(result.state[&sender(1)].info.balance, U256::from(10u64.pow(18)) - fee);
1759    }
1760
1761    #[test]
1762    fn keeps_results_on_database_errors() {
1763        let txs = [tx(1, 0, NOOP, 0)];
1764        let prewarm = Prewarm::new(&txs, &[0]);
1765        assert!(matches!(
1766            prewarm.results.take_valid(0, &mut FailingDb),
1767            Err(ProviderError::BestBlockNotFound)
1768        ));
1769        let mut state = State::builder().with_database(parent_state()).build();
1770        assert_eq!(prewarm.results.take_valid(0, &mut state).unwrap().map(drop), Ok(()));
1771    }
1772
1773    #[test]
1774    fn rejects_unknown_code() {
1775        assert_eq!(reuse_in(&[tx(1, 0, UNKNOWN_CODE, 0)], &[0], false), [Err(ReuseMiss::Stale)]);
1776    }
1777
1778    #[test]
1779    fn rejects_rebasing_unbounded_or_zero_balances() {
1780        let rebased = [tx(1, 0, sender(4), 1), tx(2, 0, sender(4), 1)];
1781        assert_eq!(reuse_in(&rebased, &[1], false), [Err(ReuseMiss::Missing), Ok(())]);
1782        for txs in [
1783            [tx(1, 0, RICH, 1), tx(2, 0, RICH, 1)],
1784            [tx(1, 0, ZERO_BALANCE, 1), tx(2, 0, ZERO_BALANCE, 1)],
1785            // Any unbounded balance read makes every balance exact.
1786            [tx(1, 0, sender(4), 1), tx(4, 0, RICH, 1)],
1787        ] {
1788            assert_eq!(
1789                reuse_in(&txs, &[1], false),
1790                [Err(ReuseMiss::Missing), Err(ReuseMiss::Stale)]
1791            );
1792        }
1793    }
1794}