Skip to content

Commit c47b8d6

Browse files
fix: pin block for entirety of EVM execution loop
1 parent 9dfbf9b commit c47b8d6

File tree

2 files changed

+43
-37
lines changed

2 files changed

+43
-37
lines changed

ethereum/src/evm.rs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{collections::HashMap, marker::PhantomData, mem, sync::Arc};
33
use alloy::{
44
consensus::{BlockHeader, TxType},
55
eips::BlockId,
6-
network::TransactionBuilder,
6+
network::{primitives::HeaderResponse, BlockResponse, TransactionBuilder},
77
rpc::types::{state::StateOverride, Block, Header, Transaction, TransactionRequest},
88
};
99
use eyre::Result;
@@ -55,7 +55,18 @@ impl<E: ExecutionProvider<Ethereum>> EthereumEvm<E> {
5555
validate_tx: bool,
5656
state_overrides: Option<StateOverride>,
5757
) -> Result<(ExecutionResult, HashMap<Address, Account>), EvmError> {
58-
let mut db = ProofDB::new(self.block_id, self.execution.clone(), state_overrides);
58+
let block = self
59+
.execution
60+
.get_block(self.block_id, false)
61+
.await
62+
.map_err(|err| EvmError::Generic(err.to_string()))?
63+
.ok_or(ExecutionError::BlockNotFound(self.block_id))
64+
.map_err(|err| EvmError::Generic(err.to_string()))?;
65+
66+
// Pin block id to a specific hash for the entire EVM run
67+
let pinned_block_id: BlockId = block.header().hash().into();
68+
69+
let mut db = ProofDB::new(pinned_block_id, self.execution.clone(), state_overrides);
5970
_ = db.state.prefetch_state(tx, validate_tx).await;
6071

6172
// Track iterations for debugging
@@ -78,7 +89,7 @@ impl<E: ExecutionProvider<Ethereum>> EthereumEvm<E> {
7889
}
7990

8091
// Create EVM after any async operations
81-
let context = self.get_context(tx, self.block_id, validate_tx).await?;
92+
let context = self.get_context(tx, &block, validate_tx);
8293

8394
// Execute in a scope to ensure EVM is dropped before any potential async operations
8495
let (result, needs_update) = {
@@ -96,21 +107,13 @@ impl<E: ExecutionProvider<Ethereum>> EthereumEvm<E> {
96107
tx_res.map_err(|err| EvmError::Generic(format!("generic: {err}")))
97108
}
98109

99-
async fn get_context(
110+
fn get_context(
100111
&self,
101112
tx: &TransactionRequest,
102-
block_id: BlockId,
113+
block: &Block<Transaction, Header>,
103114
validate_tx: bool,
104-
) -> Result<Context, EvmError> {
105-
let block = self
106-
.execution
107-
.get_block(block_id, false)
108-
.await
109-
.map_err(|err| EvmError::Generic(err.to_string()))?
110-
.ok_or(ExecutionError::BlockNotFound(block_id))
111-
.map_err(|err| EvmError::Generic(err.to_string()))?;
112-
113-
let spec = get_spec_id_for_block_timestamp(block.header.timestamp(), &self.fork_schedule);
115+
) -> Context {
116+
let spec = get_spec_id_for_block_timestamp(block.header().timestamp(), &self.fork_schedule);
114117
let mut tx_env = Self::tx_env(tx, spec);
115118

116119
if <TxType as Into<u8>>::into(
@@ -123,17 +126,17 @@ impl<E: ExecutionProvider<Ethereum>> EthereumEvm<E> {
123126
}
124127

125128
let mut cfg = CfgEnv::default();
126-
cfg.spec = get_spec_id_for_block_timestamp(block.header.timestamp, &self.fork_schedule);
129+
cfg.spec = get_spec_id_for_block_timestamp(block.header().timestamp(), &self.fork_schedule);
127130
cfg.chain_id = self.chain_id;
128131
cfg.disable_block_gas_limit = !validate_tx;
129132
cfg.disable_eip3607 = !validate_tx;
130133
cfg.disable_base_fee = !validate_tx;
131134
cfg.disable_nonce_check = !validate_tx;
132135

133-
Ok(Context::mainnet()
136+
Context::mainnet()
134137
.with_tx(tx_env)
135-
.with_block(Self::block_env(&block, &self.fork_schedule))
136-
.with_cfg(cfg))
138+
.with_block(Self::block_env(block, &self.fork_schedule))
139+
.with_cfg(cfg)
137140
}
138141

139142
fn tx_env(tx: &TransactionRequest, spec: SpecId) -> TxEnv {

opstack/src/evm.rs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{collections::HashMap, marker::PhantomData, mem, sync::Arc};
33
use alloy::{
44
consensus::BlockHeader,
55
eips::BlockId,
6-
network::TransactionBuilder,
6+
network::{primitives::HeaderResponse, BlockResponse, TransactionBuilder},
77
rpc::types::{state::StateOverride, Block, Header},
88
};
99
use eyre::Result;
@@ -59,7 +59,18 @@ impl<E: ExecutionProvider<OpStack>> OpStackEvm<E> {
5959
validate_tx: bool,
6060
state_overrides: Option<StateOverride>,
6161
) -> Result<(ExecutionResult<OpHaltReason>, HashMap<Address, Account>), EvmError> {
62-
let mut db = ProofDB::new(self.block_id, self.execution.clone(), state_overrides);
62+
let block = self
63+
.execution
64+
.get_block(self.block_id, false)
65+
.await
66+
.map_err(|err| EvmError::Generic(err.to_string()))?
67+
.ok_or(ExecutionError::BlockNotFound(self.block_id))
68+
.map_err(|err| EvmError::Generic(err.to_string()))?;
69+
70+
// Pin block id to a specific hash for the entire EVM run
71+
let pinned_block_id: BlockId = block.header().hash().into();
72+
73+
let mut db = ProofDB::new(pinned_block_id, self.execution.clone(), state_overrides);
6374
_ = db.state.prefetch_state(tx, validate_tx).await;
6475

6576
// Track iterations for debugging
@@ -82,7 +93,7 @@ impl<E: ExecutionProvider<OpStack>> OpStackEvm<E> {
8293
}
8394

8495
// Create EVM after any async operations
85-
let context = self.get_context(tx, self.block_id, validate_tx).await?;
96+
let context = self.get_context(tx, &block, validate_tx);
8697

8798
// Execute in a scope to ensure EVM is dropped before any potential async operations
8899
let (result, needs_update) = {
@@ -100,20 +111,12 @@ impl<E: ExecutionProvider<OpStack>> OpStackEvm<E> {
100111
tx_res.map_err(|err| EvmError::Generic(format!("generic: {err}")))
101112
}
102113

103-
async fn get_context(
114+
fn get_context(
104115
&self,
105116
tx: &OpTransactionRequest,
106-
block_id: BlockId,
117+
block: &Block<Transaction, Header>,
107118
validate_tx: bool,
108-
) -> Result<OpContext<EmptyDB>, EvmError> {
109-
let block = self
110-
.execution
111-
.get_block(block_id, false)
112-
.await
113-
.map_err(|err| EvmError::Generic(err.to_string()))?
114-
.ok_or(ExecutionError::BlockNotFound(block_id))
115-
.map_err(|err| EvmError::Generic(err.to_string()))?;
116-
119+
) -> OpContext<EmptyDB> {
117120
let mut tx_env = Self::tx_env(tx);
118121

119122
if <OpTxType as Into<u8>>::into(
@@ -126,7 +129,7 @@ impl<E: ExecutionProvider<OpStack>> OpStackEvm<E> {
126129
}
127130

128131
let mut cfg = CfgEnv::default();
129-
cfg.spec = get_spec_id_for_block_timestamp(block.header.timestamp(), &self.fork_schedule);
132+
cfg.spec = get_spec_id_for_block_timestamp(block.header().timestamp(), &self.fork_schedule);
130133
cfg.chain_id = self.chain_id;
131134
cfg.disable_block_gas_limit = !validate_tx;
132135
cfg.disable_eip3607 = !validate_tx;
@@ -136,10 +139,10 @@ impl<E: ExecutionProvider<OpStack>> OpStackEvm<E> {
136139
let mut op_tx_env = OpTransaction::new(tx_env);
137140
op_tx_env.enveloped_tx = Some(Bytes::new());
138141

139-
Ok(Context::op()
142+
Context::op()
140143
.with_tx(op_tx_env)
141-
.with_block(Self::block_env(&block, &self.fork_schedule))
142-
.with_cfg(cfg))
144+
.with_block(Self::block_env(block, &self.fork_schedule))
145+
.with_cfg(cfg)
143146
}
144147

145148
fn tx_env(tx: &OpTransactionRequest) -> TxEnv {

0 commit comments

Comments
 (0)