Browse Source

add pod2 blob example flow code

main
arnaucube 1 month ago
commit
13ca6ba9fe
7 changed files with 5331 additions and 0 deletions
  1. +1
    -0
      .gitignore
  2. +5172
    -0
      Cargo.lock
  3. +17
    -0
      Cargo.toml
  4. +6
    -0
      README.md
  5. BIN
      proof_with_public_inputs.bin
  6. +3
    -0
      rust-toolchain.toml
  7. +132
    -0
      src/main.rs

+ 1
- 0
.gitignore

@ -0,0 +1 @@
/target

+ 5172
- 0
Cargo.lock
File diff suppressed because it is too large
View File


+ 17
- 0
Cargo.toml

@ -0,0 +1,17 @@
[package]
name = "pod2_blob_example"
version = "0.1.0"
edition = "2024"
[dependencies]
alloy = { version = "1.0.13", features = [
"eips",
"full",
"json-rpc",
"rpc-client",
] }
tokio = {version="1.45", features = ["rt-multi-thread", "macros"]}
anyhow = "1.0.56"
pod2 = { git="https://github.com/0xPARC/pod2", rev = "78b49f2437bc6e00be2c371cbf7ac5218792d4d0" }
pod2_onchain = { git = "https://github.com/0xPARC/pod2-onchain.git", rev = "0fa4ab2b4a462b70f2ef284a8a562ea2364d9563" }

+ 6
- 0
README.md

@ -0,0 +1,6 @@
# pod2-blob-example
Example of storing a [pod2](https://github.com/0xPARC/pod2) proof (plonky2 proof) in an ethereum blob ([EIP-4844](https://www.eip4844.com/)). More details at the `src/main.rs` file.
## Usage
- set the ethereum private key and rpc url into `PRIV_KEY` and `RPC_URL` from `src/main.rs`
- run `cargo run --release`

BIN
proof_with_public_inputs.bin


+ 3
- 0
rust-toolchain.toml

@ -0,0 +1,3 @@
[toolchain]
channel = "nightly-2025-09-04"
components = ["clippy", "rustfmt"]

+ 132
- 0
src/main.rs

@ -0,0 +1,132 @@
use alloy::{
consensus::{SidecarBuilder, SimpleCoder},
eips::eip4844::DATA_GAS_PER_BLOB,
network::{TransactionBuilder, TransactionBuilder4844},
primitives::Address,
providers::{Provider, ProviderBuilder},
rpc::types::TransactionRequest,
signers::local::PrivateKeySigner,
};
use anyhow::Result;
use std::{
fs,
fs::File,
io::{BufReader, Read, Write},
time::Instant,
};
use pod2::{
backends::plonky2::{basetypes::DEFAULT_VD_SET, mainpod::Prover},
frontend::{MainPodBuilder, Operation},
middleware::{containers::Set, Params},
};
// ethereum private key to use for the tx
const PRIV_KEY: &str = "PLACE THE ETHEREUM PRIV KEY HERE";
// ethereum node rpc url
const RPC_URL: &str = "PLACE THE RPC URL HERE";
// returns a MainPod, example adapted from pod2/examples/main_pod_points.rs
pub fn compute_pod_proof() -> Result<pod2::frontend::MainPod> {
let params = Params {
max_input_pods: 0,
..Default::default()
};
let mut builder = MainPodBuilder::new(&params, &DEFAULT_VD_SET);
let set_entries = [1, 2, 3].into_iter().map(|n| n.into()).collect();
let set = Set::new(10, set_entries)?;
builder.pub_op(Operation::set_contains(set, 1))?;
let prover = Prover {};
let pod = builder.prove(&prover).unwrap();
Ok(pod)
}
#[tokio::main]
async fn main() -> Result<()> {
// PART 1: generate a pod2 proof, and wrap it into one level recursive proof
// in order to shrink its size
// use the compute_pod_proof to obtain an example pod2 proof
println!("start to generate a pod2 proof");
let start = Instant::now();
let pod = compute_pod_proof()?;
println!(
"[TIME] generate pod & compute pod proof took: {:?}",
start.elapsed()
);
// generate new plonky2 proof from POD's proof. This is 1 extra recursion in
// order to shrink the proof size, together with removing extra custom gates
let start = Instant::now();
let (verifier_data, common_circuit_data, proof_with_pis) = pod2_onchain::prove_pod(pod)?;
println!("[TIME] plonky2 (wrapper) proof took: {:?}", start.elapsed());
// get the compressed proof, which we will send inside a blob
let compressed_proof = proof_with_pis.compress(
&verifier_data.verifier_only.circuit_digest,
&common_circuit_data.common,
)?;
let compressed_proof_bytes = compressed_proof.to_bytes();
// store it in a file just in case we want to check it later
let mut file = fs::File::create("proof_with_public_inputs.bin")?;
file.write_all(&compressed_proof_bytes)?;
dbg!(&compressed_proof_bytes.len());
// alternatively, instead of generating the pod2 proof, we can load a
// previously stored proof with public inputs from the file
/*
let file = File::open("./proof_with_public_inputs.bin")?;
let mut reader = BufReader::new(file);
let mut compressed_proof_bytes = Vec::new();
reader.read_to_end(&mut compressed_proof_bytes)?;
*/
println!("size of proof_with_pis: {}", compressed_proof_bytes.len());
// PART 2: send the pod2 proof into a tx blob
let signer: PrivateKeySigner = PRIV_KEY.parse()?;
let provider = ProviderBuilder::new()
.wallet(signer.clone())
.connect(RPC_URL)
.await?;
let latest_block = provider.get_block_number().await?;
println!("Latest block number: {latest_block}");
let alice = signer.address();
let bob = Address::from([0x42; 20]);
dbg!(&alice);
dbg!(&bob);
let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(&compressed_proof_bytes);
let sidecar = sidecar.build()?;
let tx = TransactionRequest::default()
// 'from' field is filled by signer's first address (Alice in our case)
.with_to(bob)
.with_blob_sidecar(sidecar);
let pending_tx = provider.send_transaction(tx).await?;
println!("Pending transaction... tx hash: {}", pending_tx.tx_hash());
let receipt = pending_tx.get_receipt().await?;
println!(
"Transaction included in block {}",
receipt.block_number.expect("Failed to get block number")
);
assert_eq!(receipt.from, alice);
assert_eq!(receipt.to, Some(bob));
assert_eq!(
receipt
.blob_gas_used
.expect("Expected to be EIP-4844 transaction"),
DATA_GAS_PER_BLOB
);
Ok(())
}

Loading…
Cancel
Save