Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(l1,levm): remove coupling LEVM and REVM #2083

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion .github/workflows/ci_l2_prover.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
- name: RISC-V SP1 toolchain install
run: |
curl -L https://sp1.succinct.xyz | bash
~/.sp1/bin/sp1up --version 4.0.0
~/.sp1/bin/sp1up --version 4.1.0
- name: Build prover and SP1's zkVM
run: |
cd crates/l2/prover
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ run-hive-all: build-image setup-hive ## 🧪 Run all Hive testing suites
run-hive-debug: build-image setup-hive ## 🐞 Run Hive testing suite in debug mode
cd hive && ./hive --sim $(SIMULATION) --client ethrex --sim.loglevel $(SIM_LOG_LEVEL) --sim.limit "$(TEST_PATTERN)" --docker.output

run-hive-debug-levm: build-image setup-hive ## 🐞 Run Hive testing suite with LEVM in debug mode
cd hive && ./hive --client ethrex --ethrex.flags "--evm levm" --sim $(SIMULATION) --sim.limit "$(TEST_PATTERN)" --docker.output

clean-hive-logs: ## 🧹 Clean Hive logs
rm -rf ./hive/workspace/logs

Expand Down
17 changes: 5 additions & 12 deletions cmd/ef_tests/state/runner/levm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ use ethrex_levm::{
Environment,
};
use ethrex_storage::AccountUpdate;
use ethrex_vm::{
backends::{self},
db::StoreWrapper,
};
use ethrex_vm::backends::{self};
use keccak_hash::keccak;
use std::{collections::HashMap, sync::Arc};

Expand Down Expand Up @@ -94,11 +91,7 @@ pub fn prepare_vm_for_tx(
test: &EFTest,
fork: &Fork,
) -> Result<VM, EFTestRunnerError> {
let (initial_state, block_hash) = utils::load_initial_state(test);
let db = Arc::new(StoreWrapper {
store: initial_state.database().unwrap().clone(),
block_hash,
});
let db = Arc::new(utils::load_initial_state_levm(test));

let tx = test
.transactions
Expand Down Expand Up @@ -315,11 +308,11 @@ pub fn ensure_post_state(
}
// Execution result was successful and no exception was expected.
None => {
let (initial_state, block_hash) = utils::load_initial_state(test);
let store_wrapper = utils::load_initial_state_levm(test);
let levm_account_updates = backends::levm::LEVM::get_state_transitions(
Some(*fork),
&initial_state,
block_hash,
&store_wrapper.store,
store_wrapper.block_hash,
&execution_report.new_state,
)
.map_err(|_| {
Expand Down
15 changes: 6 additions & 9 deletions cmd/ef_tests/state/runner/revm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
report::{ComparisonReport, EFTestReport, EFTestReportForkResult, TestReRunReport, TestVector},
runner::{levm_runner::post_state_root, EFTestRunnerError, InternalError},
types::EFTest,
utils::{effective_gas_price, load_initial_state},
utils::{effective_gas_price, load_initial_state, load_initial_state_levm},
};
use bytes::Bytes;
use ethrex_common::{
Expand Down Expand Up @@ -327,20 +327,17 @@ pub fn ensure_post_state(
Some(_expected_exception) => {}
// We only want to compare account updates when no exception is expected.
None => {
let (initial_state, block_hash) = load_initial_state(test);
let store_wrapper = load_initial_state_levm(test);
let levm_account_updates = backends::levm::LEVM::get_state_transitions(
Some(*fork),
&initial_state,
block_hash,
&store_wrapper.store,
store_wrapper.block_hash,
&levm_execution_report.new_state,
)
.map_err(|_| {
InternalError::Custom("Error at LEVM::get_state_transitions()".to_owned())
})?;
let revm_account_updates = backends::revm_b::REVM::get_state_transitions(revm_state)
.map_err(|_| {
InternalError::Custom("Error at REVM::get_state_transitions()".to_owned())
})?;
let revm_account_updates = backends::revm_b::REVM::get_state_transitions(revm_state);
let account_updates_report = compare_levm_revm_account_updates(
vector,
test,
Expand Down Expand Up @@ -522,7 +519,7 @@ pub fn _ensure_post_state_revm(
// Execution result was successful and no exception was expected.
None => {
let revm_account_updates =
backends::revm_b::REVM::get_state_transitions(revm_state).unwrap();
backends::revm_b::REVM::get_state_transitions(revm_state);
let pos_state_root = post_state_root(&revm_account_updates, test);
let expected_post_state_root_hash =
test.post.vector_post_value(vector, *fork).hash;
Expand Down
18 changes: 17 additions & 1 deletion cmd/ef_tests/state/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use crate::{
};
use ethrex_common::{types::Genesis, H256, U256};
use ethrex_storage::{EngineType, Store};
use ethrex_vm::db::{evm_state, EvmState};
use ethrex_vm::db::{evm_state, EvmState, StoreWrapper};
use spinoff::Spinner;

/// Loads initial state, used for REVM as it contains EvmState.
pub fn load_initial_state(test: &EFTest) -> (EvmState, H256) {
let genesis = Genesis::from(test);

Expand All @@ -22,6 +23,21 @@ pub fn load_initial_state(test: &EFTest) -> (EvmState, H256) {
)
}

/// Loads initial state, function for LEVM as it does not require EvmState
pub fn load_initial_state_levm(test: &EFTest) -> StoreWrapper {
let genesis = Genesis::from(test);

let storage = Store::new("./temp", EngineType::InMemory).expect("Failed to create Store");
storage.add_initial_state(genesis.clone()).unwrap();

let block_hash = genesis.get_block().header.compute_block_hash();

StoreWrapper {
store: storage,
block_hash,
}
}

pub fn spinner_update_text_or_print(spinner: &mut Spinner, text: String, spinner_enabled: bool) {
if !spinner_enabled {
println!("{}", text);
Expand Down
4 changes: 2 additions & 2 deletions cmd/ethrex/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::{Arg, ArgAction, Command};
use ethrex_p2p::types::Node;
use ethrex_vm::backends::EVM;
use ethrex_vm::backends::EvmImplementation;
use tracing::Level;

pub fn cli() -> Command {
Expand Down Expand Up @@ -138,7 +138,7 @@ pub fn cli() -> Command {
.required(false)
.default_value("revm")
.value_name("EVM_BACKEND")
.value_parser(clap::value_parser!(EVM))
.value_parser(clap::value_parser!(EvmImplementation))
.help("Has to be `levm` or `revm`"),
)
.subcommand(
Expand Down
11 changes: 7 additions & 4 deletions cmd/ethrex/ethrex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use ethrex_p2p::{
};
use ethrex_rlp::decode::RLPDecode;
use ethrex_storage::{EngineType, Store};
use ethrex_vm::backends::EVM;
use ethrex_vm::backends::{EvmImplementation, EVM};
use k256::ecdsa::SigningKey;
use local_ip_address::local_ip;
use rand::rngs::OsRng;
Expand Down Expand Up @@ -158,8 +158,6 @@ async fn main() {

let sync_mode = sync_mode(&matches);

let evm = matches.get_one::<EVM>("evm").unwrap_or(&EVM::REVM);

let path = path::PathBuf::from(data_dir.clone());
let store: Store = if path.ends_with("memory") {
Store::new(&data_dir, EngineType::InMemory).expect("Failed to create Store")
Expand All @@ -177,7 +175,12 @@ async fn main() {
}
Store::new(&data_dir, engine_type).expect("Failed to create Store")
};
let blockchain = Blockchain::new(evm.clone(), store.clone());
let evm_impl = matches
.get_one::<EvmImplementation>("evm")
.unwrap_or(&EvmImplementation::REVM);
let evm = EVM::new(evm_impl.clone(), store.clone());

let blockchain = Blockchain::new(evm, store.clone());

let genesis = read_genesis_file(&network);
store
Expand Down
29 changes: 16 additions & 13 deletions crates/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ use std::{ops::Div, time::Instant};

use ethrex_storage::error::StoreError;
use ethrex_storage::Store;
use ethrex_vm::backends::BlockExecutionResult;
use ethrex_vm::backends::EVM;
use ethrex_vm::db::evm_state;
use ethrex_vm::backends::EvmImplementation;
use ethrex_vm::backends::{BlockExecutionResult, EVM};
use fork_choice::apply_fork_choice;
use tracing::{error, info, warn};

Expand All @@ -43,12 +42,17 @@ impl Blockchain {

pub fn default_with_store(store: Store) -> Self {
Self {
vm: Default::default(),
vm: EVM::new(EvmImplementation::REVM, store.clone()),
storage: store,
}
}

pub fn add_block(&self, block: &Block) -> Result<(), ChainError> {
info!(
"Add block: Adding block {} with hash {:#x}.",
block.header.number,
block.hash()
);
let since = Instant::now();

let block_hash = block.header.compute_block_hash();
Expand All @@ -59,23 +63,22 @@ impl Blockchain {
self.storage.add_pending_block(block.clone())?;
return Err(ChainError::ParentNotFound);
};
let mut state = evm_state(self.storage.clone(), block.header.parent_hash);
let chain_config = state.chain_config().map_err(ChainError::from)?;

let chain_config = self.storage.get_chain_config()?;

// Validate the block pre-execution
validate_block(block, &parent_header, &chain_config)?;
let BlockExecutionResult {
receipts,
requests,
account_updates,
} = self.vm.execute_block(block, &mut state)?;
} = self.vm.execute_block(block)?;

validate_gas_used(&receipts, &block.header)?;

// Apply the account updates over the last block's state and compute the new state root
let new_state_root = state
.database()
.ok_or(ChainError::StoreError(StoreError::MissingStore))?
let new_state_root = self
.storage
.apply_account_updates(block.header.parent_hash, &account_updates)?
.ok_or(ChainError::ParentStateNotFound)?;

Expand Down Expand Up @@ -138,12 +141,12 @@ impl Blockchain {
}
if let Some(last_block) = blocks.last() {
let hash = last_block.hash();
match self.vm {
EVM::LEVM => {
match self.vm.evm_impl {
EvmImplementation::LEVM => {
// We are allowing this not to unwrap so that tests can run even if block execution results in the wrong root hash with LEVM.
let _ = apply_fork_choice(&self.storage, hash, hash, hash);
}
EVM::REVM => {
EvmImplementation::REVM => {
apply_fork_choice(&self.storage, hash, hash, hash).unwrap();
}
}
Expand Down
27 changes: 12 additions & 15 deletions crates/blockchain/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ pub fn calc_excess_blob_gas(

pub struct PayloadBuildContext<'a> {
pub payload: &'a mut Block,
pub evm_state: &'a mut EvmState,
pub evm_state: EvmState,
pub block_cache: CacheDB,
pub remaining_gas: u64,
pub receipts: Vec<Receipt>,
Expand All @@ -189,8 +189,9 @@ pub struct PayloadBuildContext<'a> {
}

impl<'a> PayloadBuildContext<'a> {
fn new(payload: &'a mut Block, evm_state: &'a mut EvmState) -> Result<Self, EvmError> {
let config = evm_state.chain_config()?;
fn new(payload: &'a mut Block, storage: &Store) -> Result<Self, EvmError> {
let config = storage.get_chain_config()?;
let evm_state = evm_state(storage.clone(), payload.header.parent_hash);
let base_fee_per_blob_gas = calculate_base_fee_per_blob_gas(
payload.header.excess_blob_gas.unwrap_or_default(),
config
Expand Down Expand Up @@ -243,8 +244,7 @@ impl Blockchain {
let gas_limit = payload.header.gas_limit;

debug!("Building payload");
let mut evm_state = evm_state(self.storage.clone(), payload.header.parent_hash);
let mut context = PayloadBuildContext::new(payload, &mut evm_state)?;
let mut context = PayloadBuildContext::new(payload, &self.storage)?;
self.apply_system_operations(&mut context)?;
self.apply_withdrawals(&mut context)?;
self.fill_transactions(&mut context)?;
Expand Down Expand Up @@ -278,7 +278,7 @@ impl Blockchain {
self.vm
.process_withdrawals(
withdrawals,
context.evm_state,
&mut context.evm_state,
&context.payload.header,
&mut context.block_cache,
)
Expand All @@ -292,12 +292,10 @@ impl Blockchain {
&self,
context: &mut PayloadBuildContext,
) -> Result<(), EvmError> {
let chain_config = context.chain_config()?;
self.vm.apply_system_calls(
context.evm_state,
&mut context.evm_state,
&context.payload.header,
&mut context.block_cache,
&chain_config,
)
}

Expand Down Expand Up @@ -506,13 +504,11 @@ impl Blockchain {
head: &HeadTransaction,
context: &mut PayloadBuildContext,
) -> Result<Receipt, ChainError> {
let chain_config = context.chain_config()?;
let (report, gas_used) = self.vm.execute_tx(
context.evm_state,
&mut context.evm_state,
&head.tx,
&context.payload.header,
&mut context.block_cache,
&chain_config,
&mut context.remaining_gas,
)?;
context.block_value += U256::from(gas_used) * head.tip;
Expand All @@ -529,7 +525,7 @@ impl Blockchain {

let requests = self.vm.extract_requests(
&context.receipts,
context.evm_state,
&mut context.evm_state,
&context.payload.header,
&mut context.block_cache,
);
Expand All @@ -542,9 +538,10 @@ impl Blockchain {
}

fn finalize_payload(&self, context: &mut PayloadBuildContext) -> Result<(), ChainError> {
let parent_hash = context.payload.header.parent_hash;
let account_updates = self.vm.get_state_transitions(
context.evm_state,
context.parent_hash(),
&mut context.evm_state,
parent_hash,
&context.block_cache,
)?;

Expand Down
12 changes: 4 additions & 8 deletions crates/l2/proposer/l1_committer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use ethrex_rpc::clients::eth::{
eth_sender::Overrides, BlockByNumber, EthClient, WrappedTransaction,
};
use ethrex_storage::{error::StoreError, Store};
use ethrex_vm::{backends::EVM, db::evm_state};
use ethrex_vm::backends::EVM;
use keccak_hash::keccak;
use secp256k1::SecretKey;
use std::{collections::HashMap, str::FromStr, time::Duration};
Expand Down Expand Up @@ -254,18 +254,14 @@ impl Committer {
) -> Result<StateDiff, CommitterError> {
info!("Preparing state diff for block {}", block.header.number);

let mut state = evm_state(store.clone(), block.header.parent_hash);

let result = EVM::default()
.execute_block(block, &mut state)
let result = EVM::default_with_storage(store.clone())
.execute_block(block)
.map_err(CommitterError::from)?;
let account_updates = result.account_updates;

let mut modified_accounts = HashMap::new();
for account_update in &account_updates {
let prev_nonce = match state
.database()
.ok_or(CommitterError::FailedToRetrieveDataFromStorage)?
let prev_nonce = match store
// If we want the state_diff of a batch, we will have to change the -1 with the `batch_size`
// and we may have to keep track of the latestCommittedBlock (last block of the batch),
// the batch_size and the latestCommittedBatch in the contract.
Expand Down
Loading