-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(zk_toolbox): Add contract verifier support for zk toolbox (#2420)
## What ❔ Add contract verifier support for zk toolbox --------- Signed-off-by: Danil <[email protected]> Co-authored-by: Danil <[email protected]>
- Loading branch information
1 parent
6cc3f17
commit d10a24b
Showing
10 changed files
with
529 additions
and
1 deletion.
There are no files selected for viewing
169 changes: 169 additions & 0 deletions
169
zk_toolbox/crates/zk_inception/src/commands/contract_verifier/args/init.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
use anyhow::Context; | ||
use clap::Parser; | ||
use common::PromptSelect; | ||
use xshell::Shell; | ||
|
||
use super::releases::{get_releases_with_arch, Arch, Version}; | ||
use crate::messages::{ | ||
MSG_ARCH_NOT_SUPPORTED_ERR, MSG_FETCHING_VYPER_RELEASES_SPINNER, | ||
MSG_FETCHING_ZKSOLC_RELEASES_SPINNER, MSG_FETCHING_ZKVYPER_RELEASES_SPINNER, | ||
MSG_FETCH_SOLC_RELEASES_SPINNER, MSG_GET_SOLC_RELEASES_ERR, MSG_GET_VYPER_RELEASES_ERR, | ||
MSG_GET_ZKSOLC_RELEASES_ERR, MSG_GET_ZKVYPER_RELEASES_ERR, MSG_NO_VERSION_FOUND_ERR, | ||
MSG_OS_NOT_SUPPORTED_ERR, MSG_SOLC_VERSION_PROMPT, MSG_VYPER_VERSION_PROMPT, | ||
MSG_ZKSOLC_VERSION_PROMPT, MSG_ZKVYPER_VERSION_PROMPT, | ||
}; | ||
|
||
#[derive(Debug, Clone, Parser, Default)] | ||
pub struct InitContractVerifierArgs { | ||
/// Version of zksolc to install | ||
#[clap(long)] | ||
pub zksolc_version: Option<String>, | ||
/// Version of zkvyper to install | ||
#[clap(long)] | ||
pub zkvyper_version: Option<String>, | ||
/// Version of solc to install | ||
#[clap(long)] | ||
pub solc_version: Option<String>, | ||
/// Version of vyper to install | ||
#[clap(long)] | ||
pub vyper_version: Option<String>, | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct InitContractVerifierArgsFinal { | ||
pub zksolc_releases: Vec<Version>, | ||
pub zkvyper_releases: Vec<Version>, | ||
pub solc_releases: Vec<Version>, | ||
pub vyper_releases: Vec<Version>, | ||
} | ||
|
||
impl InitContractVerifierArgs { | ||
pub fn fill_values_with_prompt( | ||
self, | ||
shell: &Shell, | ||
) -> anyhow::Result<InitContractVerifierArgsFinal> { | ||
let arch = get_arch()?; | ||
|
||
let zksolc_releases = get_releases_with_arch( | ||
shell, | ||
"matter-labs/zksolc-bin", | ||
arch, | ||
MSG_FETCHING_ZKSOLC_RELEASES_SPINNER, | ||
) | ||
.context(MSG_GET_ZKSOLC_RELEASES_ERR)?; | ||
|
||
let zkvyper_releases = get_releases_with_arch( | ||
shell, | ||
"matter-labs/zkvyper-bin", | ||
arch, | ||
MSG_FETCHING_ZKVYPER_RELEASES_SPINNER, | ||
) | ||
.context(MSG_GET_ZKVYPER_RELEASES_ERR)?; | ||
|
||
let solc_releases = get_releases_with_arch( | ||
shell, | ||
"ethereum/solc-bin", | ||
arch, | ||
MSG_FETCH_SOLC_RELEASES_SPINNER, | ||
) | ||
.context(MSG_GET_SOLC_RELEASES_ERR)?; | ||
|
||
let vyper_releases = get_releases_with_arch( | ||
shell, | ||
"vyperlang/vyper", | ||
arch, | ||
MSG_FETCHING_VYPER_RELEASES_SPINNER, | ||
) | ||
.context(MSG_GET_VYPER_RELEASES_ERR)?; | ||
|
||
let zksolc_version = select_min_version( | ||
self.zksolc_version, | ||
zksolc_releases.clone(), | ||
MSG_ZKSOLC_VERSION_PROMPT, | ||
)?; | ||
let zksolc_releases = get_releases_above_version(zksolc_releases, zksolc_version)?; | ||
|
||
let zkvyper_version = select_min_version( | ||
self.zkvyper_version, | ||
zkvyper_releases.clone(), | ||
MSG_ZKVYPER_VERSION_PROMPT, | ||
)?; | ||
let zkvyper_releases = get_releases_above_version(zkvyper_releases, zkvyper_version)?; | ||
|
||
let solc_version = select_min_version( | ||
self.solc_version, | ||
solc_releases.clone(), | ||
MSG_SOLC_VERSION_PROMPT, | ||
)?; | ||
let solc_releases = get_releases_above_version(solc_releases, solc_version)?; | ||
|
||
let vyper_version = select_min_version( | ||
self.vyper_version, | ||
vyper_releases.clone(), | ||
MSG_VYPER_VERSION_PROMPT, | ||
)?; | ||
let vyper_releases = get_releases_above_version(vyper_releases, vyper_version)?; | ||
|
||
Ok(InitContractVerifierArgsFinal { | ||
zksolc_releases, | ||
zkvyper_releases, | ||
solc_releases, | ||
vyper_releases, | ||
}) | ||
} | ||
} | ||
|
||
fn get_arch() -> anyhow::Result<Arch> { | ||
let os = std::env::consts::OS; | ||
let arch = std::env::consts::ARCH; | ||
|
||
let arch = match os { | ||
"linux" => match arch { | ||
"x86_64" => Arch::LinuxAmd, | ||
"aarch64" => Arch::LinuxArm, | ||
"arm" => Arch::LinuxArm, | ||
_ => anyhow::bail!(MSG_ARCH_NOT_SUPPORTED_ERR), | ||
}, | ||
"macos" => match arch { | ||
"x86_64" => Arch::MacosAmd, | ||
"aarch64" => Arch::MacosArm, | ||
"arm" => Arch::MacosArm, | ||
_ => anyhow::bail!(MSG_ARCH_NOT_SUPPORTED_ERR), | ||
}, | ||
_ => anyhow::bail!(MSG_OS_NOT_SUPPORTED_ERR), | ||
}; | ||
|
||
Ok(arch) | ||
} | ||
|
||
fn select_min_version( | ||
selected: Option<String>, | ||
versions: Vec<Version>, | ||
prompt_msg: &str, | ||
) -> anyhow::Result<Version> { | ||
let selected = selected.unwrap_or_else(|| { | ||
PromptSelect::new(prompt_msg, versions.iter().map(|r| &r.version)) | ||
.ask() | ||
.into() | ||
}); | ||
|
||
let selected = versions | ||
.iter() | ||
.find(|r| r.version == selected) | ||
.context(MSG_NO_VERSION_FOUND_ERR)? | ||
.to_owned(); | ||
|
||
Ok(selected) | ||
} | ||
|
||
fn get_releases_above_version( | ||
releases: Vec<Version>, | ||
version: Version, | ||
) -> anyhow::Result<Vec<Version>> { | ||
let pos = releases | ||
.iter() | ||
.position(|r| r.version == version.version) | ||
.context(MSG_NO_VERSION_FOUND_ERR)?; | ||
|
||
Ok(releases[..=pos].to_vec()) | ||
} |
2 changes: 2 additions & 0 deletions
2
zk_toolbox/crates/zk_inception/src/commands/contract_verifier/args/mod.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod init; | ||
pub mod releases; |
159 changes: 159 additions & 0 deletions
159
zk_toolbox/crates/zk_inception/src/commands/contract_verifier/args/releases.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
use std::str::FromStr; | ||
|
||
use common::{cmd::Cmd, spinner::Spinner}; | ||
use serde::Deserialize; | ||
use xshell::{cmd, Shell}; | ||
|
||
use crate::messages::{MSG_INVALID_ARCH_ERR, MSG_NO_RELEASES_FOUND_ERR}; | ||
|
||
#[derive(Deserialize)] | ||
struct GitHubRelease { | ||
tag_name: String, | ||
assets: Vec<GitHubAsset>, | ||
} | ||
|
||
#[derive(Deserialize)] | ||
struct GitHubAsset { | ||
name: String, | ||
browser_download_url: String, | ||
} | ||
|
||
#[derive(Deserialize)] | ||
struct SolcList { | ||
builds: Vec<SolcBuild>, | ||
} | ||
|
||
#[derive(Deserialize)] | ||
struct SolcBuild { | ||
path: String, | ||
version: String, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
pub struct Version { | ||
pub version: String, | ||
pub arch: Vec<Arch>, | ||
pub url: String, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Copy)] | ||
pub enum Arch { | ||
LinuxAmd, | ||
LinuxArm, | ||
MacosAmd, | ||
MacosArm, | ||
} | ||
|
||
impl std::str::FromStr for Arch { | ||
type Err = anyhow::Error; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
if s.contains("linux-amd64") { | ||
Ok(Arch::LinuxAmd) | ||
} else if s.contains("linux-arm64") { | ||
Ok(Arch::LinuxArm) | ||
} else if s.contains("macosx-amd64") { | ||
Ok(Arch::MacosAmd) | ||
} else if s.contains("macosx-arm64") { | ||
Ok(Arch::MacosArm) | ||
} else { | ||
Err(anyhow::anyhow!(MSG_INVALID_ARCH_ERR)) | ||
} | ||
} | ||
} | ||
|
||
fn get_compatible_archs(asset_name: &str) -> anyhow::Result<Vec<Arch>> { | ||
if let Ok(arch) = Arch::from_str(asset_name) { | ||
Ok(vec![arch]) | ||
} else if asset_name.contains(".linux") { | ||
Ok(vec![Arch::LinuxAmd, Arch::LinuxArm]) | ||
} else if asset_name.contains(".darwin") { | ||
Ok(vec![Arch::MacosAmd, Arch::MacosArm]) | ||
} else { | ||
Err(anyhow::anyhow!(MSG_INVALID_ARCH_ERR)) | ||
} | ||
} | ||
|
||
fn get_releases(shell: &Shell, repo: &str, arch: Arch) -> anyhow::Result<Vec<Version>> { | ||
if repo == "ethereum/solc-bin" { | ||
return get_solc_releases(shell, arch); | ||
} | ||
|
||
let response: std::process::Output = Cmd::new(cmd!( | ||
shell, | ||
"curl https://api.github.com/repos/{repo}/releases" | ||
)) | ||
.run_with_output()?; | ||
|
||
let response = String::from_utf8(response.stdout)?; | ||
let releases: Vec<GitHubRelease> = serde_json::from_str(&response)?; | ||
|
||
let mut versions = vec![]; | ||
|
||
for release in releases { | ||
let version = release.tag_name; | ||
for asset in release.assets { | ||
let arch = match get_compatible_archs(&asset.name) { | ||
Ok(arch) => arch, | ||
Err(_) => continue, | ||
}; | ||
let url = asset.browser_download_url; | ||
versions.push(Version { | ||
version: version.clone(), | ||
arch, | ||
url, | ||
}); | ||
} | ||
} | ||
|
||
Ok(versions) | ||
} | ||
|
||
fn get_solc_releases(shell: &Shell, arch: Arch) -> anyhow::Result<Vec<Version>> { | ||
let (arch_str, compatible_archs) = match arch { | ||
Arch::LinuxAmd => ("linux-amd64", vec![Arch::LinuxAmd, Arch::LinuxArm]), | ||
Arch::LinuxArm => ("linux-amd64", vec![Arch::LinuxAmd, Arch::LinuxArm]), | ||
Arch::MacosAmd => ("macosx-amd64", vec![Arch::MacosAmd, Arch::MacosArm]), | ||
Arch::MacosArm => ("macosx-amd64", vec![Arch::MacosAmd, Arch::MacosArm]), | ||
}; | ||
|
||
let response: std::process::Output = Cmd::new(cmd!( | ||
shell, | ||
"curl https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/{arch_str}/list.json" | ||
)) | ||
.run_with_output()?; | ||
|
||
let response = String::from_utf8(response.stdout)?; | ||
let solc_list: SolcList = serde_json::from_str(&response)?; | ||
|
||
let mut versions = vec![]; | ||
for build in solc_list.builds { | ||
let path = build.path; | ||
versions.push(Version { | ||
version: build.version, | ||
arch: compatible_archs.clone(), | ||
url: format!("https://github.com/ethereum/solc-bin/raw/gh-pages/{arch_str}/{path}"), | ||
}); | ||
} | ||
versions.reverse(); | ||
Ok(versions) | ||
} | ||
|
||
pub fn get_releases_with_arch( | ||
shell: &Shell, | ||
repo: &str, | ||
arch: Arch, | ||
message: &str, | ||
) -> anyhow::Result<Vec<Version>> { | ||
let spinner = Spinner::new(message); | ||
let releases = get_releases(shell, repo, arch)?; | ||
let releases = releases | ||
.into_iter() | ||
.filter(|r| r.arch.contains(&arch)) | ||
.collect::<Vec<_>>(); | ||
if releases.is_empty() { | ||
anyhow::bail!(MSG_NO_RELEASES_FOUND_ERR); | ||
} | ||
spinner.finish(); | ||
Ok(releases) | ||
} |
Oops, something went wrong.