Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Commit

Permalink
Add jerigon run mode
Browse files Browse the repository at this point in the history
  • Loading branch information
cpubot committed Nov 3, 2023
1 parent 416359c commit e269f56
Show file tree
Hide file tree
Showing 10 changed files with 726 additions and 20 deletions.
493 changes: 483 additions & 10 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
clap = { version = "4.4.6", features = ["derive"] }
tokio = { version = "1.33.0", features = ["full"] }
serde = "1.0.183"
plonky_block_proof_gen = { git = "https://github.com/0xPolygonZero/plonky-block-proof-gen.git", rev = "935f6265fc3797acd6d81a73511e29107167721a" }
proof_protocol_decoder = { git = "https://github.com/0xPolygonZero/proof-protocol-decoder.git", rev = "cff12f6d90785a5ae984eb767e1ad83c147fc705" }
plonky_block_proof_gen = { git = "https://github.com/0xPolygonZero/plonky-block-proof-gen.git", rev = "687ebf6e0cf7f56993fd3eae5abb5f182441374f" }
proof_protocol_decoder = { git = "https://github.com/0xPolygonZero/proof-protocol-decoder.git", rev = "145dffc9b85c3d816aa71975e1218c95fcaa1817" }
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ A composition of [`paladin`](https://github.com/0xPolygonZero/paladin) and [`plo
- [Input mode](#input-mode)
- [stdin](#stdin)
- [HTTP](#http)
- [Jerigon](#jerigon)
- [Docker](#docker)


Expand Down Expand Up @@ -53,9 +54,13 @@ Usage: leader [OPTIONS]
Options:
-m, --mode <MODE>
The input mode. If `stdio`, the input is read from stdin. If `http`, the input is read from HTTP requests [default: std-io] [possible values: std-io, http]
The input mode. If `std-io`, the input is read from stdin. If `http`, the input is read from HTTP requests. If `jerigon`, the input is read from the `debug_traceBlockByNumber` and `eth_getBlockByNumber` RPC methods from Jerigon [default: std-io] [possible values: std-io, http, jerigon]
-p, --port <PORT>
The port to listen on when using the `http` mode [default: 8080]
--rpc-url <RPC_URL>
The RPC URL to use when using the `jerigon` mode
-b, --block-number <BLOCK_NUMBER>
The block number to use when using the `jerigon` mode
-t, --task-bus-routing-key <TASK_BUS_ROUTING_KEY>
Specifies the routing key for publishing task messages. In most cases, the default value should suffice [default: task]
-s, --serializer <SERIALIZER>
Expand Down Expand Up @@ -99,7 +104,11 @@ RUST_LOG=debug cargo r --release --bin leader -- --mode http --runtime in-memory
```

### Input mode
Pass JSON encoded prover input to stdin or over HTTP. See [`prover_input.rs`](/leader/src/prover_input.rs) for the input format. The examples below assume some prover input is stored in `./block_121.json`.
Pass JSON encoded prover input to stdin or over HTTP, or point the leader to a Jerigon RPC endpoint to retrieve the prover input from the `debug_traceBlockByNumber` and `eth_getBlockByNumber` RPC methods.

See [`prover_input.rs`](/leader/src/prover_input.rs) for the input format.

The `std-io` and `http` examples below assume some prover input is stored in `./block_121.json`.

#### stdin

Expand All @@ -119,6 +128,11 @@ Once initialized, send a request:
curl -X POST -H "Content-Type: application/json" -d @./block_121.json http://localhost:8080/prove
```

#### Jerigon

```bash
RUST_LOG=debug cargo r --release --bin leader -- --mode jerigon --runtime in-memory --rpc-url <RPC_URL> --block-number 16
```
## Docker

Docker images are provided for both the [leader](leader.Dockerfile) and [worker](worker.Dockerfile) binaries.
5 changes: 5 additions & 0 deletions leader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ proof_protocol_decoder = { workspace = true }
serde_json = "1.0.107"
axum = "0.6.20"
ops = { path = "../ops" }
serde_path_to_error = "0.1.14"
reqwest = { version = "0.11.22", features = ["json"] }
thiserror = "1.0.50"
ethereum-types = "0.14.1"
plonky2_evm = { git = "https://github.com/0xPolygonZero/plonky2.git", rev = "49976ea2a98dcb6052bd6cf3a65f730e55727330" }
15 changes: 12 additions & 3 deletions leader/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,29 @@ use paladin::config::Config;

#[derive(Parser)]
pub(crate) struct Cli {
/// The input mode. If `stdio`, the input is read from stdin. If `http`, the
/// input is read from HTTP requests.
/// The input mode. If `std-io`, the input is read from stdin. If `http`,
/// the input is read from HTTP requests. If `jerigon`, the input is
/// read from the `debug_traceBlockByNumber` and `eth_getBlockByNumber`
/// RPC methods from Jerigon.
#[arg(short, long, value_enum, default_value_t = Mode::StdIo)]
pub(crate) mode: Mode,
/// The port to listen on when using the `http` mode.
#[arg(short, long, default_value_t = 8080)]
pub(crate) port: u16,
/// The RPC URL to use when using the `jerigon` mode.
#[arg(long, required_if_eq("mode", "jerigon"))]
pub(crate) rpc_url: Option<String>,
/// The block number to use when using the `jerigon` mode.
#[arg(short, long, required_if_eq("mode", "jerigon"))]
pub(crate) block_number: Option<u64>,
#[command(flatten)]
pub paladin_options: Config,
pub(crate) paladin_options: Config,
}

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, ValueEnum, Default)]
pub(crate) enum Mode {
#[default]
StdIo,
Http,
Jerigon,
}
1 change: 1 addition & 0 deletions leader/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub const MATIC_CHAIN_ID: u64 = 137;
9 changes: 9 additions & 0 deletions leader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ use ops::Ops;
use paladin::runtime::Runtime;

mod cli;
mod config;
mod http;
mod init;
mod prover_input;
mod rpc;
mod stdio;

#[tokio::main]
Expand All @@ -26,6 +28,13 @@ async fn main() -> Result<()> {
Mode::Http => {
http::http_main(runtime, args.port).await?;
}
Mode::Jerigon => {
let rpc_url = args.rpc_url.expect("rpc-url is required in jerigon mode");
let block_number = args
.block_number
.expect("block-number is required in jerigon mode");
rpc::rpc_main(runtime, &rpc_url, block_number).await?;
}
}

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions leader/src/prover_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub(crate) struct ProverInput {
block_trace: BlockTrace,
other_data: OtherBlockData,
pub(crate) block_trace: BlockTrace,
pub(crate) other_data: OtherBlockData,
}

fn resolve_code_hash_fn(_: &CodeHash) -> Vec<u8> {
Expand Down
193 changes: 193 additions & 0 deletions leader/src/rpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
use anyhow::Result;
use ethereum_types::{Address, Bloom, H256, U256};
use paladin::runtime::Runtime;
use plonky2_evm::proof::{BlockHashes, BlockMetadata};
use proof_protocol_decoder::{
trace_protocol::{BlockTrace, BlockTraceTriePreImages, TxnInfo},
types::{BlockLevelData, OtherBlockData},
};
use reqwest::IntoUrl;
use serde::Deserialize;
use thiserror::Error;
use tokio::try_join;
use tracing::{debug, info};

use crate::{config::MATIC_CHAIN_ID, prover_input::ProverInput};

#[derive(Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
#[allow(clippy::large_enum_variant)]
enum JerigonResultItem {
Result(TxnInfo),
BlockWitness(BlockTraceTriePreImages),
}

/// The response from the `debug_traceBlockByNumber` RPC method.
#[derive(Deserialize, Debug)]
struct JerigonTraceResponse {
result: Vec<JerigonResultItem>,
}

#[derive(Error, Debug)]
enum JerigonTraceError {
#[error("expected BlockTraceTriePreImages in block_witness key")]
BlockTraceTriePreImagesNotFound,
}

impl TryFrom<JerigonTraceResponse> for BlockTrace {
type Error = JerigonTraceError;

fn try_from(value: JerigonTraceResponse) -> Result<Self, Self::Error> {
let mut txn_info = Vec::new();
let mut trie_pre_images = None;

for item in value.result {
match item {
JerigonResultItem::Result(info) => {
txn_info.push(info);
}
JerigonResultItem::BlockWitness(pre_images) => {
trie_pre_images = Some(pre_images);
}
}
}

let trie_pre_images =
trie_pre_images.ok_or(JerigonTraceError::BlockTraceTriePreImagesNotFound)?;

Ok(Self {
txn_info,
trie_pre_images,
})
}
}

impl JerigonTraceResponse {
/// Fetches the block trace for the given block number.
async fn fetch<U: IntoUrl>(rpc_url: U, block_number: u64) -> Result<Self> {
let client = reqwest::Client::new();
let block_number_hex = format!("0x{:x}", block_number);
info!("Fetching block trace for block {}", block_number_hex);

let result: JerigonTraceResponse = client
.post(rpc_url)
.json(&serde_json::json!({
"jsonrpc": "2.0",
"method": "debug_traceBlockByNumber",
"params": [&block_number_hex, {"tracer": "zeroTracer"}],
"id": 1,
}))
.send()
.await?
.json()
.await?;

Ok(result)
}
}

#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct EthGetBlockByNumberResult {
base_fee_per_gas: U256,
difficulty: U256,
gas_limit: U256,
gas_used: U256,
hash: H256,
logs_bloom: Bloom,
miner: Address,
mix_hash: H256,
number: U256,
timestamp: U256,
}

/// The response from the `eth_getBlockByNumber` RPC method.
#[derive(Deserialize, Debug)]
struct EthGetBlockByNumberResponse {
result: EthGetBlockByNumberResult,
}

impl From<EthGetBlockByNumberResponse> for OtherBlockData {
fn from(value: EthGetBlockByNumberResponse) -> Self {
let mut bloom = [U256::zero(); 8];

for (i, word) in value
.result
.logs_bloom
.as_fixed_bytes()
.chunks_exact(32)
.enumerate()
{
bloom[i] = U256::from_big_endian(word);
}

let block_metadata = BlockMetadata {
block_beneficiary: value.result.miner,
block_timestamp: value.result.timestamp,
block_number: value.result.number,
block_difficulty: value.result.difficulty,
block_random: value.result.mix_hash,
block_gaslimit: value.result.gas_limit,
block_chain_id: MATIC_CHAIN_ID.into(),
block_base_fee: value.result.base_fee_per_gas,
block_gas_used: value.result.gas_used,
block_bloom: bloom,
};

Self {
b_data: BlockLevelData {
b_meta: block_metadata,
b_hashes: BlockHashes {
prev_hashes: Default::default(),
cur_hash: value.result.hash,
},
},
genesis_state_trie_root: Default::default(),
}
}
}

impl EthGetBlockByNumberResponse {
/// Fetches the block metadata for the given block number.
async fn fetch<U: IntoUrl>(rpc_url: U, block_number: u64) -> Result<Self> {
let client = reqwest::Client::new();
let block_number_hex = format!("0x{:x}", block_number);
info!("Fetching block metadata for block {}", block_number_hex);

let result: EthGetBlockByNumberResponse = client
.post(rpc_url)
.json(&serde_json::json!({
"jsonrpc": "2.0",
"method": "eth_getBlockByNumber",
"params": [&block_number_hex, false],
"id": 1,
}))
.send()
.await?
.json()
.await?;

Ok(result)
}
}

/// The main function for the jerigon mode.
pub(crate) async fn rpc_main(runtime: Runtime, rpc_url: &str, block_number: u64) -> Result<()> {
let (trace_result, block_result) = try_join!(
JerigonTraceResponse::fetch(rpc_url, block_number),
EthGetBlockByNumberResponse::fetch(rpc_url, block_number)
)?;

debug!("Got block result: {:?}", block_result);
debug!("Got trace result: {:?}", trace_result);

let prover_input = ProverInput {
block_trace: trace_result.try_into()?,
other_data: block_result.into(),
};

let proof = prover_input.prove(&runtime).await?;
info!("Successfully proved {:#?}", proof);

Ok(())
}
4 changes: 3 additions & 1 deletion leader/src/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ pub(crate) async fn stdio_main(runtime: Runtime) -> Result<()> {
let mut buffer = String::new();
std::io::stdin().read_to_string(&mut buffer)?;

let input: ProverInput = serde_json::from_str(&buffer)?;
let des = &mut serde_json::Deserializer::from_str(&buffer);
let input: ProverInput = serde_path_to_error::deserialize(des)?;

let proof = input.prove(&runtime).await?;
info!("Successfully proved {:#?}", proof);

Expand Down

0 comments on commit e269f56

Please sign in to comment.