From 329daf874c20bf08e998598a61b5f7754a8f7832 Mon Sep 17 00:00:00 2001 From: Zach Obront Date: Mon, 26 Aug 2024 17:26:09 -0500 Subject: [PATCH] docs: `op-succinct` End to End tutorial (#57) * correct links in tutorial * update vkey generation in contracts/README * cargo run --bin vkey --release * docs: tutorial * add * add * clean * fix: verify key * fix * docs * fix: tutorial --------- Co-authored-by: Ratan Kaliani Co-authored-by: Ubuntu --- README.md | 2 +- contracts/README.md | 2 +- contracts/zkconfig.json | 2 +- justfile | 20 ++++ ...OP_PROPOSER.md => OP_SUCCINCT_PROPOSER.md} | 2 +- op-succinct-proposer/TUTORIAL.md | 109 ++++++++++++++++++ op-succinct-proposer/bin/vkey.rs | 12 +- 7 files changed, 135 insertions(+), 14 deletions(-) rename op-succinct-proposer/{OP_PROPOSER.md => OP_SUCCINCT_PROPOSER.md} (96%) create mode 100644 op-succinct-proposer/TUTORIAL.md diff --git a/README.md b/README.md index d5469dbd..55f4ef58 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Standalone repo to use Kona & SP1 to verify OP Stack blocks. ## Running `op-succinct` -For instructions on generating validity proofs for an OP Stack chain, refer to the [`op-succinct` Guide](./op-succinct-proposer/OP_PROPOSER.md). +For instructions on how to upgrade an OP Stack chain to use ZK validity proofs, refer to the [`op-succinct` Guide](./op-succinct-proposer/TUTORIAL.md). ## Estimating Cycle Counts diff --git a/contracts/README.md b/contracts/README.md index 3c43b152..f1891fba 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -38,5 +38,5 @@ The `ZKL2OutputOracle.sol` contract requires a verification key to be able to ve This key can be generated by running the following command from the root of the repo: ```shell -just generate-agg-vkey +cargo run --bin vkey --release ``` diff --git a/contracts/zkconfig.json b/contracts/zkconfig.json index e0c64ede..763dc213 100644 --- a/contracts/zkconfig.json +++ b/contracts/zkconfig.json @@ -11,4 +11,4 @@ "vkey": "0x0000000000000000000000000000000000000000000000000000000000000000", "verifierGateway": "0x3B6041173B80E77f038f3F2C0f9744f04837185e", "l2OutputOracleProxy": "0xdfe97868233d1aa22e815a266982f2cf17685a27" -} +} \ No newline at end of file diff --git a/justfile b/justfile index a45af8ac..b7b43635 100644 --- a/justfile +++ b/justfile @@ -80,3 +80,23 @@ run-client-native l2_block_num l1_rpc='${L1_RPC}' l1_beacon_rpc='${L1_BEACON_RPC # Output the data required for the ZKVM execution. echo "$L1_HEAD $L2_OUTPUT_ROOT $L2_CLAIM $L2_BLOCK_NUMBER $L2_CHAIN_ID" + +upgrade-l2oo l1_rpc admin_pk etherscan_api_key="": + #!/usr/bin/env bash + + CHAIN_ID=$(jq -r '.chainId' contracts/zkconfig.json) + if [ "$CHAIN_ID" = "0" ] || [ -z "$CHAIN_ID" ]; then + echo "Are you sure you've filled out your zkconfig.json? Your chain ID is currently set to 0." + exit 1 + fi + + VERIFY="" + ETHERSCAN_API_KEY="{{etherscan_api_key}}" + if [ $ETHERSCAN_API_KEY != "" ]; then + VERIFY="--verify --verifier etherscan --etherscan-api-key $ETHERSCAN_API_KEY" + fi + + L1_RPC="{{l1_rpc}}" + ADMIN_PK="{{admin_pk}}" + + cd contracts && forge script script/ZKUpgrader.s.sol:ZKUpgrader --rpc-url $L1_RPC --private-key $ADMIN_PK $VERIFY --broadcast --slow \ No newline at end of file diff --git a/op-succinct-proposer/OP_PROPOSER.md b/op-succinct-proposer/OP_SUCCINCT_PROPOSER.md similarity index 96% rename from op-succinct-proposer/OP_PROPOSER.md rename to op-succinct-proposer/OP_SUCCINCT_PROPOSER.md index f3fdd389..3a06f448 100644 --- a/op-succinct-proposer/OP_PROPOSER.md +++ b/op-succinct-proposer/OP_SUCCINCT_PROPOSER.md @@ -1,4 +1,4 @@ -# Run OP Proposer +# Run the `op-succinct` Proposer ## Instructions diff --git a/op-succinct-proposer/TUTORIAL.md b/op-succinct-proposer/TUTORIAL.md new file mode 100644 index 00000000..b51cbd01 --- /dev/null +++ b/op-succinct-proposer/TUTORIAL.md @@ -0,0 +1,109 @@ +# `op-succinct` Tutorial + +This tutorial guides you through upgrading an existing OP Stack chain to a ZK-OP Stack chain. It assumes you already have a running OP Stack chain. If not, please follow [Optimism's tutorial](https://docs.optimism.io/builders/chain-operators/tutorials/create-l2-rollup) first. + +## Prerequisites + +Before starting, ensure you have: + +1. Access to the Admin keys for upgrading L1 contracts of the OP Stack chain. +2. Fault proofs turned off (you should be using `L2OutputOracle`, not `FaultDisputeGameFactory` for output roots). +3. Stopped the original `op-proposer`. +4. At least 1 ETH in your `PROPOSER` wallet. +5. All dependencies from the Optimism tutorial installed. +6. Your L2 geth node running with `--gcmode=archive` and `--state.scheme=hash` flags. You can do this with [ops-anton](https://github.com/anton-rs/ops-anton/blob/main/L2/op-mainnet/op-geth/op-geth.sh). + +## Overview + +At a high level, the `op-succinct` upgrade focuses on replacing the `op-proposer` component and its associated contracts. This change allows the chain to progress only with ZK-proven blocks, while keeping the other components (`op-geth`, `op-batcher`, and `op-node`) unchanged. + +When an OP Stack chain is running, there are 4 main components: +1. `op-geth` (Sequencer mode): Takes transactions from users and uses them to generate blocks and execute blocks. +2. `op-batcher`: Batches transactions from users and submits them to the L1. +3. `op-node`: Reads batch data from L1 and uses it to drive `op-geth` in non-sequencer mode to perform state transitions. +4. `op-proposer`: Posts an output root to L1 at regular intervals, which captures the L2 state so withdrawals can be processed. + +## Step-by-Step Guide + +### Step 1: Setup + +1. Clone the `op-succinct` repo: + ``` + git clone https://github.com/succinctlabs/op-succinct.git + ``` + +2. Create and fill in the environment files: + ``` + cp .env.example .env + cp .env.server.example .env.server + ``` + +3. Fill in the `contracts/zkconfig.json` file with your chain's specific details. + +
+ Field Info + + - `startingBlockNumber`: The L2 block number at which the rollup starts. Default should be 0. + - `l2RollupNode`: The URL of the L2 rollup node. (After the tutorial, this is `http://localhost:8545`) + - `submissionInterval`: The number of L2 blocks between each L1 output submission. + - `l2BlockTime`: The time in seconds between each L2 block. + - `proposer`: The Ethereum address of the proposer account. If `address(0)`, anyone can submit proofs. + - `challenger`: The Ethereum address of the challenger account. If `address(0)`, no one can dispute proofs. + - `finalizationPeriod`: The time period (in seconds) after which a proposed output becomes finalized. Specifically, the time period after + which you can withdraw your funds against the proposed output. + - `chainId`: The chain ID of the L2 network. + - `owner`: The Ethereum address of the `ZKL2OutputOracle` owner, who can update the verification key and verifier address. + - `vkey`: The verification key for the aggregate program. Run `cargo run --bin vkey --release` to generate this. + - `verifierGateway`: The address of the verifier gateway contract. + - `l2OutputOracleProxy`: The address of your OP Stack chain's L2 Output Oracle proxy contract which will be upgraded. + +
+ +### Step 2: Deploy ZKL2OutputOracle + +1. Navigate to the contracts directory: + ``` + cd contracts + ``` + +2. Run the upgrade script: + ``` + forge script script/ZKUpgrader.s.sol:ZKUpgrader --rpc-url --private-key --verify --verifier etherscan --etherscan-api-key --broadcast --slow --vvvv + ``` + Alternatively, use: + ``` + just upgrade-l2oo + ``` + +To run your OP Stack chain with ZK proofs you need to replace your chain's `L2OutputOracle` with `ZKL2OutputOracle`. + +The existing `L2OutputOracle` allows a permissioned `proposer` role to submit output roots. The permissioned `challenger` role can dispute these output roots. There are no checks on the validity of these claims. + +The ZKL2OutputOracle makes the following changes: +- Require a valid SP1 proof for each output root submission. +- If `proposer == address(0)`, anyone can submit a proof. + +### Step 3: Launch `op-succinct` + +1. Build and start the Docker container: + ``` + docker compose build + docker compose up -d + ``` + +This launches a Docker container with `op-proposer` from a fork of the `optimism` monorepo which can be found [here](https://github.com/succinctlabs/optimism/tree/zk-proposer) as well as a server that generates ZK proofs using Kona (Optimism's state transition function library) and SP1 (a zkVM). + +The modified `op-proposer` performs the following tasks: +- Monitors L1 state to determine when to request a proof. +- Requests proofs from the Kona SP1 server. +- Once proofs have been generated for a sufficiently large range (specified by `SUBMISSION_INTERVAL` in `zkconfig.json`), aggregates batch proofs and submits them on-chain. + +## Verification + +After completing these steps, your chain will be running as a ZK-OP chain: + +- The L1 contract (ZKL2OutputOracle) verifies ZK proofs. +- The Kona SP1 server generates ZK proofs. +- The modified `op-proposer` submits ZK-proven output roots to L1. + +🎉 Congratulations! 🎉 You've successfully upgraded to a ZK-OP chain with `op-succinct`. diff --git a/op-succinct-proposer/bin/vkey.rs b/op-succinct-proposer/bin/vkey.rs index 1edb8212..061e40f2 100644 --- a/op-succinct-proposer/bin/vkey.rs +++ b/op-succinct-proposer/bin/vkey.rs @@ -1,7 +1,5 @@ -use std::str::FromStr; - -use alloy::{providers::ProviderBuilder, sol, transports::http::reqwest::Url}; -use alloy_primitives::{hex, keccak256, Address, B256}; +use alloy::sol; +use alloy_primitives::{hex, keccak256}; use anyhow::Result; use log::info; use sp1_sdk::{utils, HashableKey, ProverClient}; @@ -37,8 +35,6 @@ async fn main() -> Result<()> { dotenv::dotenv().ok(); utils::setup_logger(); - let args = Args::parse(); - let prover = ProverClient::new(); let (_, vkey) = prover.setup(MULTI_BLOCK_ELF); @@ -55,10 +51,6 @@ async fn main() -> Result<()> { let (_, agg_vk) = prover.setup(AGG_ELF); info!("Aggregation ELF Verification Key: {}", agg_vk.bytes32()); println!("Aggregation ELF Verification Key: {}", agg_vk.bytes32()); - let agg_vk_bytes: [u8; 32] = hex::decode(agg_vk.bytes32().replace("0x", "")) - .unwrap() - .try_into() - .unwrap(); Ok(()) }