mirror of
https://github.com/arnaucube/pod2-blob-example.git
synced 2026-02-10 05:06:45 +01:00
add pod2 blob example flow code
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
5172
Cargo.lock
generated
Normal file
5172
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
@@ -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
README.md
Normal file
6
README.md
Normal file
@@ -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
Normal file
BIN
proof_with_public_inputs.bin
Normal file
Binary file not shown.
3
rust-toolchain.toml
Normal file
3
rust-toolchain.toml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly-2025-09-04"
|
||||||
|
components = ["clippy", "rustfmt"]
|
||||||
132
src/main.rs
Normal file
132
src/main.rs
Normal file
@@ -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(¶ms, &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(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user