Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: zkquiz setup and testing locally/devnet #1153

Merged
merged 21 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions batcher/aligned-sdk/src/core/types.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::str::FromStr;

use ethers::core::k256::ecdsa::SigningKey;
use ethers::signers::Signer;
use ethers::signers::Wallet;
Expand Down Expand Up @@ -344,6 +346,22 @@ pub enum Network {
HoleskyStage,
}

impl FromStr for Network {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"holesky" => Ok(Network::Holesky),
"holesky-stage" => Ok(Network::HoleskyStage),
"devnet" => Ok(Network::Devnet),
_ => Err(
"Invalid network, possible values are: \"holesky\", \"holesky-stage\", \"devnet\""
.to_string(),
),
}
}
}

#[cfg(test)]
mod tests {
use ethers::signers::LocalWallet;
Expand Down
13 changes: 13 additions & 0 deletions examples/zkquiz/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
SHELL := /bin/bash

deploy_verifier:
@. ./contracts/.env && . ./contracts/deploy.sh

deploy_verifier_devnet:
@. ./contracts/.devnet.env && . ./contracts/deploy.sh

CONTRACT_ADDRESS=0xA828f1463074d26FB761c662F80194f5dB2d31D0
RPC_URL=https://ethereum-holesky-rpc.publicnode.com
VERIFICATION_DATA=./aligned_verification_data/0a1fab5df88a71e48633cbdeedc8d1a234b790d15a8a2fd04cd6a03c1e05b5ef_212.json
Expand All @@ -10,3 +15,11 @@ answer_quiz:
--keystore-path $(KEYSTORE_PATH) \
--rpc-url $(RPC_URL) \
--verifier-contract-address $(CONTRACT_ADDRESS)

answer_quiz_local:
@cd quiz/script && cargo run -r -- \
--keystore-path ../../../../config-files/devnet/keys/operator-3.ecdsa.key.json \
--rpc-url http://localhost:8545 \
--batcher-url ws://localhost:8080 \
--network devnet \
--verifier-contract-address $(CONTRACT_ADDRESS)
22 changes: 22 additions & 0 deletions examples/zkquiz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,25 @@ This will:
3. Pay & submit proof to aligned for verification
4. Wait for proof to be verified in aligned
5. Claim NFT if proof is verified

## Testing locally

If you want to test the zk quiz on a local network follow these steps:

1. Setup Aligned locally following [this guide](../../docs/3_guides/6_setup_aligned.md)

3. Move into the zkquiz example:
```
cd examples/zkquiz
```

4. Deploy the ZKQuiz verifier contract, and locate the `CONTRACT_ADDRESS` from its output:
```
make deploy_verifier_devnet
```


5. Run the quiz:
```
CONTRACT_ADDRESS=<VERIFIER_CONTRACT_ADDRESS> make answer_quiz_local
```
4 changes: 4 additions & 0 deletions examples/zkquiz/contracts/.devnet.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
RPC_URL=http://localhost:8545
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 # a rich anvil account
ALIGNED_SERVICE_MANAGER_ADDRESS=0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8
BATCHER_PAYMENT_SERVICE_ADDRESS=0x7969c5eD335650692Bc04293B07F5BF2e7A673C0
78 changes: 28 additions & 50 deletions examples/zkquiz/quiz/script/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
#![feature(slice_flatten)]

use std::io;
use std::sync::Arc;

use aligned_sdk::core::types::{
AlignedVerificationData, Network, PriceEstimate, ProvingSystemId, VerificationData,
};
use aligned_sdk::sdk::{estimate_fee, get_payment_service_address};
use aligned_sdk::sdk::{deposit_to_aligned, estimate_fee};
use aligned_sdk::sdk::{get_next_nonce, submit_and_wait_verification};
use clap::Parser;
use dialoguer::Confirm;
Expand All @@ -18,11 +16,8 @@ use sp1_sdk::{ProverClient, SP1Stdin};

abigen!(VerifierContract, "VerifierContract.json",);

const BATCHER_URL: &str = "wss://batcher.alignedlayer.com";
const ELF: &[u8] = include_bytes!("../../program/elf/riscv32im-succinct-zkvm-elf");

const NETWORK: Network = Network::Holesky;

#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
Expand All @@ -34,6 +29,10 @@ struct Args {
default_value = "https://ethereum-holesky-rpc.publicnode.com"
)]
rpc_url: String,
#[arg(short, long, default_value = "wss://batcher.alignedlayer.com")]
batcher_url: String,
#[arg(short, long, default_value = "holesky")]
network: Network,
#[arg(short, long)]
verifier_contract_address: H160,
}
Expand All @@ -48,20 +47,27 @@ async fn main() {
let keystore_password = rpassword::prompt_password("Enter keystore password: ")
.expect("Failed to read keystore password");

let wallet = LocalWallet::decrypt_keystore(args.keystore_path, &keystore_password)
.expect("Failed to decrypt keystore")
.with_chain_id(17000u64);

let provider =
Provider::<Http>::try_from(rpc_url.as_str()).expect("Failed to connect to provider");

let signer = Arc::new(SignerMiddleware::new(provider.clone(), wallet.clone()));
let chain_id = provider
.get_chainid()
.await
.expect("Failed to get chain_id");

let wallet = LocalWallet::decrypt_keystore(args.keystore_path, &keystore_password)
.expect("Failed to decrypt keystore")
.with_chain_id(chain_id.as_u64());

let signer = SignerMiddleware::new(provider.clone(), wallet.clone());

if Confirm::with_theme(&dialoguer::theme::ColorfulTheme::default())
.with_prompt("Do you want to deposit 0.004eth in Aligned ?\nIf you already deposited Ethereum to Aligned before, this is not needed")
.interact()
.expect("Failed to read user input") {
deposit_to_batcher(wallet.address(), signer.clone()).await.expect("Failed to pay for proof submission");

deposit_to_aligned(U256::from(4000000000000000u128), signer.clone(), args.network).await
.expect("Failed to pay for proof submission");
}

// Generate proof.
Expand Down Expand Up @@ -114,7 +120,7 @@ async fn main() {
pub_input: None,
};

let max_fee = estimate_fee(&rpc_url, PriceEstimate::Default)
let max_fee = estimate_fee(&rpc_url, PriceEstimate::Instant)
.await
.expect("failed to fetch gas price from the blockchain");

Expand All @@ -126,14 +132,16 @@ async fn main() {
.expect("Failed to read user input")
{ return; }

let nonce = get_next_nonce(&rpc_url, wallet.address(), NETWORK)
let nonce = get_next_nonce(&rpc_url, wallet.address(), args.network)
.await
.expect("Failed to get next nonce");

println!("Submitting your proof...");

let aligned_verification_data = submit_and_wait_verification(
BATCHER_URL,
&args.batcher_url,
&rpc_url,
NETWORK,
args.network,
&verification_data,
max_fee,
wallet.clone(),
Expand All @@ -143,9 +151,10 @@ async fn main() {
.unwrap();

println!(
"Proof submitted and verified successfully on batch {}, claiming prize...",
"Proof submitted and verified successfully on batch {}",
hex::encode(aligned_verification_data.batch_merkle_root)
);
println!("Claiming NFT prize...");

claim_nft_with_verified_proof(
&aligned_verification_data,
Expand Down Expand Up @@ -193,43 +202,12 @@ fn read_answer() -> char {
}
}

async fn deposit_to_batcher(
from: Address,
signer: Arc<SignerMiddleware<Provider<Http>, LocalWallet>>,
) -> anyhow::Result<()> {
let addr = get_payment_service_address(NETWORK);

let tx = TransactionRequest::new()
.from(from)
.to(addr)
.value(4000000000000000u128);

match signer
.send_transaction(tx, None)
.await
.map_err(|e| anyhow::anyhow!("Failed to send tx {}", e))?
.await
.map_err(|e| anyhow::anyhow!("Failed to submit tx {}", e))?
{
Some(receipt) => {
println!(
"Payment sent. Transaction hash: {:x}",
receipt.transaction_hash
);
Ok(())
}
None => {
anyhow::bail!("Payment failed");
}
}
}

async fn claim_nft_with_verified_proof(
aligned_verification_data: &AlignedVerificationData,
signer: Arc<SignerMiddleware<Provider<Http>, LocalWallet>>,
signer: SignerMiddleware<Provider<Http>, LocalWallet>,
verifier_contract_addr: &Address,
) -> anyhow::Result<()> {
let verifier_contract = VerifierContract::new(*verifier_contract_addr, signer);
let verifier_contract = VerifierContract::new(*verifier_contract_addr, signer.into());

let index_in_batch = U256::from(aligned_verification_data.index_in_batch);
let merkle_path = Bytes::from(
Expand Down
Loading