Skip to content

Commit 377f2da

Browse files
committed
wip: pevm integration for historical sync till Cancun
1 parent 75b7172 commit 377f2da

File tree

10 files changed

+371
-130
lines changed

10 files changed

+371
-130
lines changed

Cargo.lock

Lines changed: 217 additions & 47 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,16 +405,16 @@ reth-trie-common = { path = "crates/trie/common" }
405405
reth-trie-db = { path = "crates/trie/db" }
406406
reth-trie-parallel = { path = "crates/trie/parallel" }
407407

408-
# revm
409-
revm = { version = "14.0.1", features = [
408+
409+
revm = { git = "https://github.com/risechain/revm", rev = "3d71d81a33722653073ef760860613b3af4dcb23", features = [
410410
"std",
411411
"secp256k1",
412412
"blst",
413413
], default-features = false }
414-
revm-inspectors = "0.7"
415-
revm-primitives = { version = "9.0.2", features = [
414+
revm-primitives = { git = "https://github.com/risechain/revm", rev = "3d71d81a33722653073ef760860613b3af4dcb23", features = [
416415
"std",
417416
], default-features = false }
417+
revm-inspectors = { git = "https://github.com/risechain/revm-inspectors", rev = "48a2bcfadcd0f3879c279077ca4061138a177677" }
418418

419419
# eth
420420
alloy-chains = "0.1.32"
@@ -613,3 +613,4 @@ tracy-client = "0.17.3"
613613
#alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"}
614614
#alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"}
615615
#alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"}
616+
# revm

crates/ethereum/evm/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ revm-primitives.workspace = true
2828
alloy-eips.workspace = true
2929
alloy-sol-types.workspace = true
3030

31+
pevm = { git = "https://github.com/risechain/pevm", rev = "ac6283747207b287e0378c0033e06fba22abc2c2" }
32+
3133
[dev-dependencies]
3234
reth-testing-utils.workspace = true
3335
reth-revm = { workspace = true, features = ["test-utils"] }

crates/ethereum/evm/src/execute.rs

Lines changed: 97 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use crate::{
55
EthEvmConfig,
66
};
77
use alloc::{boxed::Box, sync::Arc, vec, vec::Vec};
8-
use core::fmt::Display;
8+
use core::{fmt::Display, num::NonZeroUsize};
9+
use pevm::{chain::PevmEthereum, Pevm};
910
use reth_chainspec::{ChainSpec, EthereumHardforks, MAINNET};
1011
use reth_ethereum_consensus::validate_block_post_execution;
1112
use reth_evm::{
@@ -34,7 +35,7 @@ use reth_revm::{
3435
Evm,
3536
};
3637
use revm_primitives::{
37-
db::{Database, DatabaseCommit},
38+
db::{DatabaseCommit, DatabaseRef},
3839
BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState,
3940
};
4041
use std::collections::hash_map::Entry;
@@ -71,12 +72,15 @@ where
7172
{
7273
fn eth_executor<DB>(&self, db: DB) -> EthBlockExecutor<EvmConfig, DB>
7374
where
74-
DB: Database<Error: Into<ProviderError>>,
75+
DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync,
7576
{
7677
EthBlockExecutor::new(
7778
self.chain_spec.clone(),
7879
self.evm_config.clone(),
7980
State::builder().with_database(db).with_bundle_update().without_state_clear().build(),
81+
Pevm::default(),
82+
PevmEthereum::mainnet(),
83+
NonZeroUsize::new(8).unwrap(),
8084
)
8185
}
8286
}
@@ -85,22 +89,22 @@ impl<EvmConfig> BlockExecutorProvider for EthExecutorProvider<EvmConfig>
8589
where
8690
EvmConfig: ConfigureEvm<Header = Header>,
8791
{
88-
type Executor<DB: Database<Error: Into<ProviderError> + Display>> =
92+
type Executor<DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync> =
8993
EthBlockExecutor<EvmConfig, DB>;
9094

91-
type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> =
95+
type BatchExecutor<DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync> =
9296
EthBatchExecutor<EvmConfig, DB>;
9397

9498
fn executor<DB>(&self, db: DB) -> Self::Executor<DB>
9599
where
96-
DB: Database<Error: Into<ProviderError> + Display>,
100+
DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync,
97101
{
98102
self.eth_executor(db)
99103
}
100104

101105
fn batch_executor<DB>(&self, db: DB) -> Self::BatchExecutor<DB>
102106
where
103-
DB: Database<Error: Into<ProviderError> + Display>,
107+
DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync,
104108
{
105109
let executor = self.eth_executor(db);
106110
EthBatchExecutor { executor, batch_record: BlockBatchRecord::default() }
@@ -138,14 +142,13 @@ where
138142
///
139143
/// It does __not__ apply post-execution changes that do not require an [EVM](Evm), for that see
140144
/// [`EthBlockExecutor::post_execution`].
141-
fn execute_state_transitions<Ext, DB>(
145+
fn _execute_state_transitions<Ext, DB>(
142146
&self,
143147
block: &BlockWithSenders,
144148
mut evm: Evm<'_, Ext, &mut State<DB>>,
145-
) -> Result<EthExecuteOutput, BlockExecutionError>
149+
) -> Result<(EthExecuteOutput, Vec<ResultAndState>), BlockExecutionError>
146150
where
147-
DB: Database,
148-
DB::Error: Into<ProviderError> + Display,
151+
DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync,
149152
{
150153
// apply pre execution changes
151154
apply_beacon_root_contract_call(
@@ -168,6 +171,7 @@ where
168171
// execute transactions
169172
let mut cumulative_gas_used = 0;
170173
let mut receipts = Vec::with_capacity(block.body.len());
174+
let mut results = Vec::with_capacity(block.body.len());
171175
for (sender, transaction) in block.transactions_with_sender() {
172176
// The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior,
173177
// must be no greater than the block’s gasLimit.
@@ -177,24 +181,25 @@ where
177181
transaction_gas_limit: transaction.gas_limit(),
178182
block_available_gas,
179183
}
180-
.into())
184+
.into());
181185
}
182186

183187
self.evm_config.fill_tx_env(evm.tx_mut(), transaction, *sender);
184188

185189
// Execute transaction.
186-
let ResultAndState { result, state } = evm.transact().map_err(move |err| {
190+
let result_and_state = evm.transact().map_err(move |err| {
187191
let new_err = err.map_db_err(|e| e.into());
188192
// Ensure hash is calculated for error log, if not already done
189193
BlockValidationError::EVM {
190194
hash: transaction.recalculate_hash(),
191195
error: Box::new(new_err),
192196
}
193197
})?;
194-
evm.db_mut().commit(state);
198+
results.push(result_and_state.clone());
199+
evm.db_mut().commit(result_and_state.state);
195200

196201
// append gas used
197-
cumulative_gas_used += result.gas_used();
202+
cumulative_gas_used += result_and_state.result.gas_used();
198203

199204
// Push transaction changeset and calculate header bloom filter for receipt.
200205
receipts.push(
@@ -203,10 +208,10 @@ where
203208
tx_type: transaction.tx_type(),
204209
// Success flag was added in `EIP-658: Embedding transaction status code in
205210
// receipts`.
206-
success: result.is_success(),
211+
success: result_and_state.result.is_success(),
207212
cumulative_gas_used,
208213
// convert to reth log
209-
logs: result.into_logs(),
214+
logs: result_and_state.result.into_logs(),
210215
..Default::default()
211216
},
212217
);
@@ -230,7 +235,7 @@ where
230235
vec![]
231236
};
232237

233-
Ok(EthExecuteOutput { receipts, requests, gas_used: cumulative_gas_used })
238+
Ok((EthExecuteOutput { receipts, requests, gas_used: cumulative_gas_used }, results))
234239
}
235240
}
236241

@@ -245,12 +250,29 @@ pub struct EthBlockExecutor<EvmConfig, DB> {
245250
executor: EthEvmExecutor<EvmConfig>,
246251
/// The state to use for execution
247252
state: State<DB>,
253+
/// Parallel executor
254+
pevm: Pevm,
255+
chain: PevmEthereum,
256+
concurrency_level: NonZeroUsize,
248257
}
249258

250259
impl<EvmConfig, DB> EthBlockExecutor<EvmConfig, DB> {
251260
/// Creates a new Ethereum block executor.
252-
pub const fn new(chain_spec: Arc<ChainSpec>, evm_config: EvmConfig, state: State<DB>) -> Self {
253-
Self { executor: EthEvmExecutor { chain_spec, evm_config }, state }
261+
pub const fn new(
262+
chain_spec: Arc<ChainSpec>,
263+
evm_config: EvmConfig,
264+
state: State<DB>,
265+
pevm: Pevm,
266+
chain: PevmEthereum,
267+
concurrency_level: NonZeroUsize,
268+
) -> Self {
269+
Self {
270+
executor: EthEvmExecutor { chain_spec, evm_config },
271+
state,
272+
pevm,
273+
chain,
274+
concurrency_level,
275+
}
254276
}
255277

256278
#[inline]
@@ -268,14 +290,14 @@ impl<EvmConfig, DB> EthBlockExecutor<EvmConfig, DB> {
268290
impl<EvmConfig, DB> EthBlockExecutor<EvmConfig, DB>
269291
where
270292
EvmConfig: ConfigureEvm<Header = Header>,
271-
DB: Database<Error: Into<ProviderError> + Display>,
293+
DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync,
272294
{
273295
/// Configures a new evm configuration and block environment for the given block.
274296
///
275297
/// # Caution
276298
///
277299
/// This does not initialize the tx environment.
278-
fn evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg {
300+
fn _evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg {
279301
let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default());
280302
let mut block_env = BlockEnv::default();
281303
self.executor.evm_config.fill_cfg_and_block_env(
@@ -303,16 +325,60 @@ where
303325
self.on_new_block(&block.header);
304326

305327
// 2. configure the evm and execute
306-
let env = self.evm_env_for_block(&block.header, total_difficulty);
307-
let output = {
308-
let evm = self.executor.evm_config.evm_with_env(&mut self.state, env);
309-
self.executor.execute_state_transitions(block, evm)
310-
}?;
328+
let spec_id = crate::config::revm_spec(
329+
self.chain_spec(),
330+
&reth_chainspec::Head {
331+
number: block.header.number,
332+
timestamp: block.header.timestamp,
333+
difficulty: block.header.difficulty,
334+
total_difficulty,
335+
hash: Default::default(),
336+
},
337+
);
338+
let mut block_env = BlockEnv::default();
339+
self.executor.evm_config.fill_block_env(
340+
&mut block_env,
341+
&block.header,
342+
spec_id >= revm_primitives::SpecId::MERGE,
343+
);
344+
let mut tx_envs = Vec::with_capacity(block.body.len());
345+
for (sender, transaction) in block.transactions_with_sender() {
346+
let mut tx_env = revm_primitives::TxEnv::default();
347+
self.executor.evm_config.fill_tx_env(&mut tx_env, transaction, *sender);
348+
tx_envs.push(tx_env);
349+
}
350+
let results =
351+
if tx_envs.len() < self.concurrency_level.into() || block.header.gas_used < 4_000_000 {
352+
pevm::execute_revm_sequential(&self.state, &self.chain, spec_id, block_env, tx_envs)
353+
} else {
354+
self.pevm.execute_revm_parallel(
355+
&self.state,
356+
&self.chain,
357+
spec_id,
358+
block_env,
359+
tx_envs,
360+
self.concurrency_level,
361+
)
362+
}
363+
.unwrap_or_else(|err| panic!("{:?}", err));
364+
let mut cumulative_gas_used = 0;
365+
let mut receipts = Vec::with_capacity(block.body.len());
366+
for (tx, ResultAndState { result, state }) in block.transactions().zip(results) {
367+
cumulative_gas_used += result.gas_used();
368+
receipts.push(Receipt {
369+
tx_type: tx.tx_type(),
370+
success: result.is_success(),
371+
cumulative_gas_used,
372+
logs: result.into_logs(),
373+
..Default::default()
374+
});
375+
self.state.commit(state);
376+
}
311377

312378
// 3. apply post execution changes
313379
self.post_execution(block, total_difficulty)?;
314380

315-
Ok(output)
381+
Ok(EthExecuteOutput { receipts, requests: Vec::new(), gas_used: cumulative_gas_used })
316382
}
317383

318384
/// Apply settings before a new block is executed.
@@ -357,7 +423,7 @@ where
357423
impl<EvmConfig, DB> Executor<DB> for EthBlockExecutor<EvmConfig, DB>
358424
where
359425
EvmConfig: ConfigureEvm<Header = Header>,
360-
DB: Database<Error: Into<ProviderError> + Display>,
426+
DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync,
361427
{
362428
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
363429
type Output = BlockExecutionOutput<Receipt>;
@@ -392,7 +458,7 @@ pub struct BlockAccessListExecutor<EvmConfig, DB> {
392458
impl<EvmConfig, DB> Executor<DB> for BlockAccessListExecutor<EvmConfig, DB>
393459
where
394460
EvmConfig: ConfigureEvm<Header = Header>,
395-
DB: Database<Error: Into<ProviderError> + Display>,
461+
DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync,
396462
{
397463
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
398464
type Output = BlockExecutionOutput<Receipt>;
@@ -486,7 +552,7 @@ impl<EvmConfig, DB> EthBatchExecutor<EvmConfig, DB> {
486552
impl<EvmConfig, DB> BatchExecutor<DB> for EthBatchExecutor<EvmConfig, DB>
487553
where
488554
EvmConfig: ConfigureEvm<Header = Header>,
489-
DB: Database<Error: Into<ProviderError> + Display>,
555+
DB: DatabaseRef<Error: Into<ProviderError> + Display> + Send + Sync,
490556
{
491557
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
492558
type Output = ExecutionOutcome;

crates/ethereum/payload/src/lib.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,12 @@ where
208208
// which also removes all dependent transaction from the iterator before we can
209209
// continue
210210
best_txs.mark_invalid(&pool_tx);
211-
continue
211+
continue;
212212
}
213213

214214
// check if the job was cancelled, if so we can exit early
215215
if cancel.is_cancelled() {
216-
return Ok(BuildOutcome::Cancelled)
216+
return Ok(BuildOutcome::Cancelled);
217217
}
218218

219219
// convert tx to a signed transaction
@@ -230,7 +230,7 @@ where
230230
// for regular transactions above.
231231
trace!(target: "payload_builder", tx=?tx.hash, ?sum_blob_gas_used, ?tx_blob_gas, "skipping blob transaction because it would exceed the max data gas per block");
232232
best_txs.mark_invalid(&pool_tx);
233-
continue
233+
continue;
234234
}
235235
}
236236

@@ -258,11 +258,11 @@ where
258258
best_txs.mark_invalid(&pool_tx);
259259
}
260260

261-
continue
261+
continue;
262262
}
263263
err => {
264264
// this is an error that we should treat as fatal for this attempt
265-
return Err(PayloadBuilderError::EvmExecutionError(err))
265+
return Err(PayloadBuilderError::EvmExecutionError(err));
266266
}
267267
}
268268
}
@@ -312,7 +312,7 @@ where
312312
// check if we have a better block
313313
if !is_better_payload(best_payload.as_ref(), total_fees) {
314314
// can skip building the block
315-
return Ok(BuildOutcome::Aborted { fees: total_fees, cached_reads })
315+
return Ok(BuildOutcome::Aborted { fees: total_fees, cached_reads });
316316
}
317317

318318
// calculate the requests and the requests root
@@ -363,7 +363,7 @@ where
363363
// calculate the state root
364364
let hashed_state = HashedPostState::from_bundle_state(&execution_outcome.state().state);
365365
let (state_root, trie_output) = {
366-
let state_provider = db.database.0.inner.borrow_mut();
366+
let state_provider = db.database.inner.borrow_mut();
367367
state_provider.db.state_root_with_updates(hashed_state.clone()).inspect_err(|err| {
368368
warn!(target: "payload_builder",
369369
parent_hash=%parent_block.hash(),

0 commit comments

Comments
 (0)