Skip to content

Commit

Permalink
feat(l2): prover comparison benchmarks (#1221)
Browse files Browse the repository at this point in the history
**Motivation**

To compare the L2 prover performance with rsp.

**Description**

- adds a `prove` command to the L2 CLI to prove a block from genesis and
chain files
- adds a cache for rsp containing a L1 mainnet block
- adds some rules to the prover's Makefile to run the comparison (rsp
proving a 24 MGas mainnet block, ethrex proving a 25 MGas L2 block)

---------

Co-authored-by: Javier Rodríguez Chatruc <49622509+jrchatruc@users.noreply.github.com>
  • Loading branch information
xqft and jrchatruc authored Nov 29, 2024
1 parent 450a1c7 commit 18aae39
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 5 deletions.
9 changes: 8 additions & 1 deletion cmd/ethrex_l2/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
commands::{autocomplete, config, info, stack, test, utils, wallet},
commands::{autocomplete, config, info, prove, stack, test, utils, wallet},
config::load_selected_config,
};
use clap::{Parser, Subcommand};
Expand Down Expand Up @@ -37,13 +37,19 @@ enum EthrexL2Command {
Autocomplete(autocomplete::Command),
#[clap(subcommand, about = "Gets L2's information.")]
Info(info::Command),
#[clap(about = "Read a test chain from disk and prove a block.")]
Prove(prove::Command),
}

pub async fn start() -> eyre::Result<()> {
let EthrexL2CLI { command } = EthrexL2CLI::parse();
if let EthrexL2Command::Config(cmd) = command {
return cmd.run().await;
}
if let EthrexL2Command::Prove(cmd) = command {
return cmd.run();
}

let cfg = load_selected_config().await?;
match command {
EthrexL2Command::Stack(cmd) => cmd.run(cfg).await?,
Expand All @@ -53,6 +59,7 @@ pub async fn start() -> eyre::Result<()> {
EthrexL2Command::Config(_) => unreachable!(),
EthrexL2Command::Test(cmd) => cmd.run(cfg).await?,
EthrexL2Command::Info(cmd) => cmd.run(cfg).await?,
EthrexL2Command::Prove(_) => unreachable!(),
};
Ok(())
}
1 change: 1 addition & 0 deletions cmd/ethrex_l2/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub(crate) mod autocomplete;
pub(crate) mod config;
pub(crate) mod info;
pub(crate) mod prove;
pub(crate) mod stack;
pub(crate) mod test;
pub(crate) mod utils;
Expand Down
43 changes: 43 additions & 0 deletions cmd/ethrex_l2/src/commands/prove.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use clap::Args;
use ethrex_l2::utils::test_data_io::{generate_program_input, read_chain_file, read_genesis_file};
use ethrex_prover_lib::prover::Prover;

#[derive(Args)]
pub(crate) struct Command {
#[clap(
short = 'g',
long = "genesis",
help = "Path to the file containing the genesis block."
)]
genesis: String,
#[clap(
short = 'c',
long = "chain",
help = "Path to the file containing the test chain."
)]
chain: String,
#[clap(
short = 'n',
long = "block-number",
help = "Number of the block in the test chain to prove."
)]
block_number: usize,
}

impl Command {
pub fn run(self) -> eyre::Result<()> {
let genesis = read_genesis_file(&self.genesis);
let chain = read_chain_file(&self.chain);
let program_input = generate_program_input(genesis, chain, self.block_number)?;

let mut prover = Prover::new();
prover.prove(program_input).expect("proving failed");
println!(
"Total gas consumption: {}",
prover
.get_gas()
.expect("failed to deserialize gas consumption")
);
Ok(())
}
}
1 change: 1 addition & 0 deletions crates/l2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ secp256k1.workspace = true
keccak-hash = "0.10.0"
envy = "0.4.2"
thiserror.workspace = true
zkvm_interface = { path = "./prover/zkvm/interface/", default-features = false }

# risc0
risc0-zkvm = { version = "1.1.2" }
Expand Down
2 changes: 2 additions & 0 deletions crates/l2/prover/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rsp/
target/
38 changes: 36 additions & 2 deletions crates/l2/prover/Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,44 @@
.PHONY: perf_test_proving perf_gpu rsp_comparison

ROOT_DIRECTORY := ../../..

RISC0_DEV_MODE?=1
RUST_LOG?="info"
perf_test_proving:
@echo "Using RISC0_DEV_MODE: ${RISC0_DEV_MODE}"
RISC0_DEV_MODE=${RISC0_DEV_MODE} RUST_LOG=${RUST_LOG} cargo test --release --test perf_zkvm --features build_zkvm -- --show-output
.PHONY: perf_test_proving

perf_gpu:
RUSTFLAGS="-C target-cpu=native" RISC0_DEV_MODE=0 RUST_LOG="debug" cargo test --release --test perf_zkvm --features "build_zkvm,gpu" -- --show-output
.PHONY: perf_gpu

# L2 Prover comparison with rsp. Uses GPU by default.

ETHREX_L2_BIN := ./target/release/ethrex_l2
RSP_BIN := ./target/release/rsp

GENESIS_FILE := $(ROOT_DIRECTORY)/test_data/genesis-l2-old.json
CHAIN_FILE := $(ROOT_DIRECTORY)/test_data/l2-loadtest.rlp
RSP_CACHE := $(ROOT_DIRECTORY)/test_data/rsp

rsp_comparison: $(ETHREX_L2_BIN) $(RSP_BIN)
@echo "rsp times (L1 Mainnet block, 24 MGas):"
@time $(RSP_BIN) --prove \
--chain-id 1 \
--block-number 21272632 \
--cache-dir $(RSP_CACHE) \
>/dev/null
@echo ""
@echo "ethrex_l2 times (L2 block, 25 MGas):"
@RISC0_DEV_MODE=false time $(ETHREX_L2_BIN) prove \
--genesis $(GENESIS_FILE) \
--chain $(CHAIN_FILE) \
--block-number 2 \
>/dev/null

$(ETHREX_L2_BIN):
CARGO_TARGET_DIR=target cargo build -r --manifest-path $(ROOT_DIRECTORY)/Cargo.toml --bin ethrex_l2 --features "build_zkvm,gpu,disable-dev-mode"

$(RSP_BIN):
- git clone https://github.com/succinctlabs/rsp.git
cd rsp; \
CARGO_TARGET_DIR=../target cargo build -r --bin rsp --features cuda
6 changes: 6 additions & 0 deletions crates/l2/prover/src/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ impl<'a> Prover<'a> {
Ok(())
}

pub fn get_gas(&self) -> Result<u64, Box<dyn std::error::Error>> {
Ok(risc0_zkvm::serde::from_slice(
self.stdout.get(..8).unwrap_or_default(), // first 8 bytes
)?)
}

pub fn get_commitment(
receipt: &risc0_zkvm::Receipt,
) -> Result<ProgramOutput, Box<dyn std::error::Error>> {
Expand Down
7 changes: 7 additions & 0 deletions crates/l2/prover/zkvm/interface/guest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ fn main() {
let receipts = execute_block(&block, &mut state).expect("failed to execute block");
validate_gas_used(&receipts, &block.header).expect("invalid gas used");

env::write(
&receipts
.last()
.expect("no receipts found")
.cumulative_gas_used,
);

let account_updates = get_state_transitions(&mut state);

// Update tries and calculate final state root hash
Expand Down
18 changes: 18 additions & 0 deletions crates/l2/utils/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use ethrex_blockchain::error::ChainError;
use ethrex_storage::error::StoreError;
use ethrex_vm::errors::ExecutionDBError;
use keccak_hash::H256;

#[derive(Debug, thiserror::Error)]
pub enum ProverInputError {
#[error("Invalid block number: {0}")]
InvalidBlockNumber(usize),
#[error("Invalid parent block: {0}")]
InvalidParentBlock(H256),
#[error("Store error: {0}")]
StoreError(#[from] StoreError),
#[error("Chain error: {0}")]
ChainError(#[from] ChainError),
#[error("ExecutionDB error: {0}")]
ExecutionDBError(#[from] ExecutionDBError),
}
1 change: 1 addition & 0 deletions crates/l2/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use secp256k1::SecretKey;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

pub mod config;
pub mod error;
pub mod eth_client;
pub mod merkle_tree;
pub mod test_data_io;
Expand Down
39 changes: 38 additions & 1 deletion crates/l2/utils/test_data_io.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]

use ethrex_blockchain::add_block;
use ethrex_core::types::{Block, Genesis};
use ethrex_rlp::{decode::RLPDecode, encode::RLPEncode};
use ethrex_storage::Store;
use ethrex_storage::{EngineType, Store};
use ethrex_vm::execution_db::ExecutionDB;
use tracing::info;
use zkvm_interface::io::ProgramInput;

use std::{
fs::File,
io::{BufReader, Read as _, Write},
path::PathBuf,
};

use super::error::ProverInputError;

// From cmd/ethrex
pub fn read_chain_file(chain_rlp_path: &str) -> Vec<Block> {
let chain_file = File::open(chain_rlp_path).expect("Failed to open chain rlp file");
Expand Down Expand Up @@ -53,6 +59,37 @@ pub fn generate_rlp(
Ok(())
}

pub fn generate_program_input(
genesis: Genesis,
chain: Vec<Block>,
block_number: usize,
) -> Result<ProgramInput, ProverInputError> {
let block = chain
.get(block_number)
.ok_or(ProverInputError::InvalidBlockNumber(block_number))?
.clone();

// create store
let store = Store::new("memory", EngineType::InMemory)?;
store.add_initial_state(genesis)?;
for block in chain {
add_block(&block, &store)?;
}

let parent_block_header = store
.get_block_header_by_hash(block.header.parent_hash)?
.ok_or(ProverInputError::InvalidParentBlock(
block.header.parent_hash,
))?;
let db = ExecutionDB::from_exec(&block, &store)?;

Ok(ProgramInput {
db,
block,
parent_block_header,
})
}

// From cmd/ethrex/decode.rs
fn _chain_file(file: File) -> Result<Vec<Block>, Box<dyn std::error::Error>> {
let mut chain_rlp_reader = BufReader::new(file);
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/vm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod db;
mod errors;
pub mod errors;
pub mod execution_db;
mod execution_result;
#[cfg(feature = "l2")]
Expand Down
Binary file added test_data/rsp/input/1/21272632.bin
Binary file not shown.

0 comments on commit 18aae39

Please sign in to comment.