Skip to content

Commit

Permalink
refactor(l2): new prover structure (#878)
Browse files Browse the repository at this point in the history
**Motivation**

Introduces a new structure for the L2 crates. Serves as a base for the
rest of the L2 development.

**Description**

- mostly renames and refactored modules

---------

Co-authored-by: Estéfano Bargas <estefano.bargas@fing.edu.uy>
  • Loading branch information
fborello-lambda and xqft authored Oct 23, 2024
1 parent 31dc6c0 commit f648387
Show file tree
Hide file tree
Showing 39 changed files with 584 additions and 256 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ jobs:

- name: RISC-V zkVM toolchain install
run: |
curl -L https://sp1.succinct.xyz | bash
~/.sp1/bin/sp1up
curl -L https://risczero.com/install | bash
~/.risc0/bin/rzup install
- name: Build program
- name: Build prover and zkVM
run: |
cd crates/l2/prover/sp1/program
~/.sp1/bin/cargo-prove prove build
cd crates/l2/prover
cargo build --release --features build_zkvm
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ members = [
"cmd/ethereum_rust_l2",
"crates/vm/levm",
"crates/vm/levm/bench/revm_comparison",
"crates/l2/prover",
]
resolver = "2"
default-members = ["cmd/ethereum_rust", "cmd/ethereum_rust_l2"]
default-members = ["cmd/ethereum_rust", "cmd/ethereum_rust_l2", "crates/l2/prover"]

[workspace.package]
version = "0.1.0"
Expand All @@ -32,6 +33,7 @@ ethereum_rust-vm = { path = "./crates/vm" }
ethereum_rust-trie = { path = "./crates/storage/trie" }
ethereum_rust-rlp = { path = "./crates/common/rlp" }
ethereum_rust-l2 = { path = "./crates/l2" }
ethereum_rust-prover = { path = "./crates/l2/prover" }

tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = "0.3.0"
Expand Down
2 changes: 0 additions & 2 deletions cmd/ethereum_rust/ethereum_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,6 @@ async fn main() {
if #[cfg(feature = "l2")] {
let l2_proposer = ethereum_rust_l2::start_proposer(store.clone()).into_future();
tracker.spawn(l2_proposer);
// let l2_prover = ethereum_rust_l2::start_prover().into_future();
// tracker.spawn(l2_prover);
} else if #[cfg(feature = "dev")] {
use ethereum_rust_dev;

Expand Down
6 changes: 4 additions & 2 deletions cmd/ethereum_rust_l2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ colored = "2.1.0"
spinoff = "0.8.0"
itertools = "0.13.0"
strum = "0.26.3"
libsecp256k1 = "0.7.1"
keccak-hash = "0.10.0"

ethereum_rust-l2.workspace = true
ethereum_rust-core.workspace = true
ethereum_rust-blockchain.workspace = true
ethereum_rust-prover.workspace = true
ethereum_rust-rlp.workspace = true
libsecp256k1 = "0.7.1"
keccak-hash = "0.10.0"

[[bin]]
name = "ethereum_rust_l2"
Expand Down
100 changes: 78 additions & 22 deletions cmd/ethereum_rust_l2/src/commands/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ pub(crate) enum Command {
help = "Skips L1 deployment. Beware that this will only work if the L1 is already set up. L1 contracts must be present in the config."
)]
skip_l1_deployment: bool,
#[arg(
long = "start-prover",
help = "Start ZK Prover for the L2 if set.",
short = 'p',
default_value_t = false
)]
start_prover: bool,
},
#[clap(about = "Shutdown the stack.")]
Shutdown {
Expand All @@ -37,6 +44,13 @@ pub(crate) enum Command {
l2: bool,
#[clap(short = 'y', long, help = "Forces the start without confirmation.")]
force: bool,
#[arg(
long = "start-prover",
help = "Start ZK Prover for the L2 if set.",
short = 'p',
default_value_t = false
)]
start_prover: bool,
},
#[clap(about = "Cleans up the stack. Prompts for confirmation.")]
Purge {
Expand Down Expand Up @@ -68,7 +82,10 @@ impl Command {
let l2_rpc_url = cfg.network.l2_rpc_url.clone();

match self {
Command::Init { skip_l1_deployment } => {
Command::Init {
skip_l1_deployment,
start_prover,
} => {
// Delegate the command whether to init in a local environment
// or in a testnet. If the L1 RPC URL is localhost, then it is
// a local environment and the local node needs to be started.
Expand All @@ -80,7 +97,7 @@ impl Command {
contract_deps(&contracts_path)?;
deploy_l1(&l1_rpc_url, &cfg.wallet.private_key, &contracts_path)?;
}
start_l2(root.to_path_buf(), &l2_rpc_url).await?;
start_l2(root.to_path_buf(), &l2_rpc_url, start_prover).await?;
}
Command::Shutdown { l1, l2, force } => {
if force || (l1 && confirm("Are you sure you want to shutdown the local L1 node?")?)
Expand All @@ -91,12 +108,17 @@ impl Command {
shutdown_l2()?;
}
}
Command::Start { l1, l2, force } => {
Command::Start {
l1,
l2,
force,
start_prover,
} => {
if force || l1 {
start_l1(&l2_crate_path, &ethereum_rust_dev_path).await?;
}
if force || l2 {
start_l2(root.to_path_buf(), &l2_rpc_url).await?;
start_l2(root.to_path_buf(), &l2_rpc_url, start_prover).await?;
}
}
Command::Purge { force } => {
Expand Down Expand Up @@ -133,6 +155,7 @@ impl Command {
Box::pin(async {
Self::Init {
skip_l1_deployment: false,
start_prover: false,
}
.run(cfg.clone())
.await
Expand Down Expand Up @@ -250,25 +273,58 @@ fn docker_compose_l2_up(ethereum_rust_dev_path: &Path) -> eyre::Result<()> {
Ok(())
}

async fn start_l2(root: PathBuf, l2_rpc_url: &str) -> eyre::Result<()> {
// The cli is not displaying tracing logs.
async fn start_l2(root: PathBuf, l2_rpc_url: &str, start_prover: bool) -> eyre::Result<()> {
let l2_genesis_file_path = root.join("test_data/genesis-l2.json");
let cmd = std::process::Command::new("cargo")
.arg("run")
.arg("--release")
.arg("--bin")
.arg("ethereum_rust")
.arg("--features")
.arg("l2")
.arg("--")
.arg("--network")
.arg(l2_genesis_file_path)
.arg("--http.port")
.arg(l2_rpc_url.split(':').last().unwrap())
.current_dir(root)
.spawn()?
.wait()?;
if !cmd.success() {
eyre::bail!("Failed to run L2 node");
let l2_rpc_url_owned = l2_rpc_url.to_owned();
let root_clone = root.clone();
let l2_start_cmd = std::thread::spawn(move || {
let status = std::process::Command::new("cargo")
.arg("run")
.arg("--release")
.arg("--bin")
.arg("ethereum_rust")
.arg("--features")
.arg("l2")
.arg("--")
.arg("--network")
.arg(l2_genesis_file_path)
.arg("--http.port")
.arg(l2_rpc_url_owned.split(':').last().unwrap())
.current_dir(root)
.status();

match status {
Ok(s) if s.success() => Ok(()),
Ok(_) => Err(eyre::eyre!("Failed to run L2 node")),
Err(e) => Err(eyre::eyre!(e)),
}
});

let l2_result = l2_start_cmd.join().expect("L2 thread panicked");
l2_result?;

if start_prover {
let prover_start_cmd = std::thread::spawn(|| {
let status = std::process::Command::new("cargo")
.arg("run")
.arg("--release")
.arg("--features")
.arg("build_zkvm")
.arg("--bin")
.arg("ethereum_rust_prover")
.current_dir(root_clone)
.status();

match status {
Ok(s) if s.success() => Ok(()),
Ok(_) => Err(eyre::eyre!("Failed to Initialize Prover")),
Err(e) => Err(eyre::eyre!(e)),
}
});
let prover_result = prover_start_cmd.join().expect("Prover thread panicked");
prover_result?;
}

Ok(())
}
7 changes: 5 additions & 2 deletions crates/l2/.example.env
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ ENGINE_API_RPC_URL=http://localhost:8551
ENGINE_API_JWT_PATH=./jwt.hex
PROVER_SERVER_LISTEN_IP=127.0.0.1
PROVER_SERVER_LISTEN_PORT=3000
PROVER_PROVER_SERVER_ENDPOINT=localhost:3000
PROVER_ELF_PATH=./prover/sp1/program/elf/riscv32im-succinct-zkvm-elf
PROVER_CLIENT_PROVER_SERVER_ENDPOINT=localhost:3000
PROPOSER_ON_CHAIN_PROPOSER_ADDRESS=0xF04a082b0f773cA74B61278d9dBaaB5Ed5273DB5
PROPOSER_L1_ADDRESS=0x3d1e15a1a55578f7c920884a9943b3b35d0d885b
PROPOSER_L1_PRIVATE_KEY=0x385c546456b6a603a1cfcaa9ec9494ba4832da08dd6bcf4de9a71e4a01b74924
PROPOSER_INTERVAL_MS=5000
# https://dev.risczero.com/api/generating-proofs/dev-mode
# 1/true means fake proofs
RISC0_DEV_MODE=1
RUST_LOG="[executor]=info"
5 changes: 4 additions & 1 deletion crates/l2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ ethereum_rust-dev = { path = "../../crates/blockchain/dev" }
hex.workspace = true
bytes.workspace = true
jsonwebtoken.workspace = true
sp1-sdk = "2.0.0"
libsecp256k1 = "0.7.1"
keccak-hash = "0.10.0"
envy = "0.4.2"
thiserror.workspace = true

# risc0
risc0-zkvm = { version = "1.1.2" }


[lib]
path = "./l2.rs"
3 changes: 3 additions & 0 deletions crates/l2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,6 @@ down-l2: ## 🛑 Shuts down the L2 Lambda Ethereum Rust Client
pkill -f ethereum_rust || exit 0

restart-l2: down-l2 init-l2 ## 🔄 Restarts the L2 Lambda Ethereum Rust Client

init-l2-prover: ## 🚀 Initializes the Prover
cargo run --release --features build_zkvm --manifest-path ../../Cargo.toml --bin ethereum_rust_prover
2 changes: 1 addition & 1 deletion crates/l2/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Ethereum Rust L2 is composed of three main parts:

- [General Overview](./overview.md)
- [Operator](./operator.md)
- [Proposer](./proposer.md)
- [Prover](./prover.md)
- [Contracts](./contracts.md)

Expand Down
8 changes: 5 additions & 3 deletions crates/l2/docs/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

## ToC

- [ToC](#toc)
- [L1 side](#l1-side)
- [`CommonBridge`](#commonbridge)
- [`OnChainOperator`](#blockexecutor)
- [`CommonBridge`](#commonbridge)
- [`OnChainOperator`](#onchainoperator)
- [`Verifier`](#verifier)
- [L2 side](#l2-side)
- [`L1MessageSender`](#l1messagesender)
- [`L1MessageSender`](#l1messagesender)

## L1 side

Expand Down
4 changes: 2 additions & 2 deletions crates/l2/docs/proposer.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
- [Components](#components)
- [L1 Watcher](#l1-watcher)
- [L1 Transaction Sender](#l1-transaction-sender)
- [Prover Client](#prover-client)
- [Prover Server](#prover-server)
- [Configuration](#configuration)

## Components
Expand All @@ -27,7 +27,7 @@ Commit transactions are sent when the Proposer wants to commit to a new block. T

Verify transactions are sent by the Proposer after the prover has successfully generated a proof of block execution to verify it. These transactions contain the proof to be verified in the L1.

### Prover Client
### Prover Server

TODO

Expand Down
39 changes: 26 additions & 13 deletions crates/l2/docs/prover.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,48 @@

## ToC

- [ToC](#toc)
- [Prover](#prover)
- [How to Run](#how-to-run)
- [Workflow](#workflow)
- [Configuration](#configuration)

>[!NOTE]
> The shipping/deploying process and the `Prover` itself is under development.
## Prover

The RISC-V zkVM Prover currently runs a demo fibonacci program. It uses Groth16, which requires at least 128GB of RAM. To mock proof generation and avoid RAM requirements, you can use the `SP1_PROVER=mock` env var.
The RISC-V zkVM Prover currently runs an empty program. To mock proof generation and avoid RAM requirements, you can use the following envar: `RISC0_DEV_MODE=1`. [risczero - dev-mode](https://dev.risczero.com/api/generating-proofs/dev-mode).

### How to Run

Dependencies: `cargo-risczero` [dev - risczero - installation](https://dev.risczero.com/api/zkvm/install)

If you are at `crates/l2`, you will have to set the `.env` file (the `.example.env` can be used) and then run `make init-l2-prover`.

The `build_zkvm` flag is used, if you don't have the risc0's "sdk", you can build the prover without the feature to check all the surrounding components of the `zkvm`.

## Workflow

The ProofDataClient is in charge of request for new jobs to the ProofDataProvider when the prover is free. When a new job arrives, the Prover will generate the proof and then the ProofDataClient will submit it to the ProofDataProvider
The `Prover Server` is monitoring requests for new jobs from the `Prover Client`, sent when the prover is free. When a new job arrives, the Prover will generate the proof and then the `Prover Client` will send it to the `Prover Server`.

```mermaid
sequenceDiagram
participant Prover
participant ProofDataClient
participant ProofDataProvider
ProofDataClient->>+ProofDataProvider: ProofData::Request
ProofDataProvider-->>-ProofDataClient: ProofData::Response(id)
ProofDataClient->>+Prover: Prove(id)
Prover-->>-ProofDataClient: Proof
ProofDataClient->>+ProofDataProvider: ProofData::Submit(id)
ProofDataProvider-->>-ProofDataClient: ProofData::SubmitAck(id)
participant ProverClient
participant ProverServer
ProverClient->>+ProverServer: ProofData::Request
ProverServer-->>-ProverClient: ProofData::Response(block_number, ProverInputs)
ProverClient->>+Prover: Prove(block_number, ProverInputs)
Prover-->>-ProverClient: Creates zkProof
ProverClient->>+ProverServer: ProofData::Submit(block_number, zkProof)
ProverServer-->>-ProverClient: ProofData::SubmitAck(block_number)
```

## Configuration

The following environment variables are available to configure the prover:

- `SP1_PROVER`: Prover type. Can be `local` or `mock`.
- `PROVER_PROVER_SERVER_ENDPOINT`: Endpoint to connect to the ProofDataProvider.
- `PROVER_ELF_PATH`: Path to the ELF file to prove.
- `PROVER_SERVER_LISTEN_IP`: IP used to start the Server.
- `PROVER_SERVER_LISTEN_PORT`: Port used to start the Server.
- `PROVER_CLIENT_PROVER_SERVER_ENDPOINT`: Prover Server's Endpoint used to connect the Client to the Server.
2 changes: 0 additions & 2 deletions crates/l2/l2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
pub mod proposer;
pub mod prover;
pub mod utils;

pub use proposer::start_proposer;
pub use prover::start_prover;
4 changes: 2 additions & 2 deletions crates/l2/proposer/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ pub enum L1WatcherError {
}

#[derive(Debug, thiserror::Error)]
pub enum ProofDataProviderError {
#[error("ProofDataProvider connection failed: {0}")]
pub enum ProverServerError {
#[error("ProverServer connection failed: {0}")]
ConnectionError(#[from] std::io::Error),
}

Expand Down
2 changes: 1 addition & 1 deletion crates/l2/proposer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub async fn start_proposer(store: Store) {
}

let l1_watcher = tokio::spawn(l1_watcher::start_l1_watcher(store.clone()));
let prover_server = tokio::spawn(prover_server::start_prover_server());
let prover_server = tokio::spawn(prover_server::start_prover_server(store.clone()));
let proposer = tokio::spawn(async move {
let eth_config = EthConfig::from_env().expect("EthConfig::from_env");
let proposer_config = ProposerConfig::from_env().expect("ProposerConfig::from_env");
Expand Down
Loading

0 comments on commit f648387

Please sign in to comment.