mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-07-09 22:37:24 +00:00
192 lines
5.8 KiB
Rust
192 lines
5.8 KiB
Rust
//! This module downloads solc binaries.
|
|
|
|
use std::{
|
|
collections::HashMap,
|
|
sync::{LazyLock, Mutex},
|
|
};
|
|
|
|
use revive_dt_common::types::VersionOrRequirement;
|
|
|
|
use semver::Version;
|
|
use sha2::{Digest, Sha256};
|
|
|
|
use crate::list::List;
|
|
|
|
pub static LIST_CACHE: LazyLock<Mutex<HashMap<&'static str, List>>> =
|
|
LazyLock::new(Default::default);
|
|
|
|
impl List {
|
|
pub const LINUX_URL: &str = "https://binaries.soliditylang.org/linux-amd64/list.json";
|
|
pub const WINDOWS_URL: &str = "https://binaries.soliditylang.org/windows-amd64/list.json";
|
|
pub const MACOSX_URL: &str = "https://binaries.soliditylang.org/macosx-amd64/list.json";
|
|
pub const WASM_URL: &str = "https://binaries.soliditylang.org/wasm/list.json";
|
|
|
|
/// Try to downloads the list from the given URL.
|
|
///
|
|
/// Caches the list retrieved from the `url` into [LIST_CACHE],
|
|
/// subsequent calls with the same `url` will return the cached list.
|
|
pub async fn download(url: &'static str) -> anyhow::Result<Self> {
|
|
if let Some(list) = LIST_CACHE.lock().unwrap().get(url) {
|
|
return Ok(list.clone());
|
|
}
|
|
|
|
let body: List = reqwest::get(url).await?.json().await?;
|
|
|
|
LIST_CACHE.lock().unwrap().insert(url, body.clone());
|
|
|
|
Ok(body)
|
|
}
|
|
}
|
|
|
|
/// Download solc binaries from the official SolidityLang site
|
|
#[derive(Clone, Debug)]
|
|
pub struct SolcDownloader {
|
|
pub version: Version,
|
|
pub target: &'static str,
|
|
pub list: &'static str,
|
|
}
|
|
|
|
impl SolcDownloader {
|
|
pub const BASE_URL: &str = "https://binaries.soliditylang.org";
|
|
|
|
pub const LINUX_NAME: &str = "linux-amd64";
|
|
pub const MACOSX_NAME: &str = "macosx-amd64";
|
|
pub const WINDOWS_NAME: &str = "windows-amd64";
|
|
pub const WASM_NAME: &str = "wasm";
|
|
|
|
async fn new(
|
|
version: impl Into<VersionOrRequirement>,
|
|
target: &'static str,
|
|
list: &'static str,
|
|
) -> anyhow::Result<Self> {
|
|
let version_or_requirement = version.into();
|
|
match version_or_requirement {
|
|
VersionOrRequirement::Version(version) => Ok(Self {
|
|
version,
|
|
target,
|
|
list,
|
|
}),
|
|
VersionOrRequirement::Requirement(requirement) => {
|
|
let Some(version) = List::download(list)
|
|
.await?
|
|
.builds
|
|
.into_iter()
|
|
.map(|build| build.version)
|
|
.filter(|version| requirement.matches(version))
|
|
.max()
|
|
else {
|
|
anyhow::bail!("Failed to find a version that satisfies {requirement:?}");
|
|
};
|
|
Ok(Self {
|
|
version,
|
|
target,
|
|
list,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn linux(version: impl Into<VersionOrRequirement>) -> anyhow::Result<Self> {
|
|
Self::new(version, Self::LINUX_NAME, List::LINUX_URL).await
|
|
}
|
|
|
|
pub async fn macosx(version: impl Into<VersionOrRequirement>) -> anyhow::Result<Self> {
|
|
Self::new(version, Self::MACOSX_NAME, List::MACOSX_URL).await
|
|
}
|
|
|
|
pub async fn windows(version: impl Into<VersionOrRequirement>) -> anyhow::Result<Self> {
|
|
Self::new(version, Self::WINDOWS_NAME, List::WINDOWS_URL).await
|
|
}
|
|
|
|
pub async fn wasm(version: impl Into<VersionOrRequirement>) -> anyhow::Result<Self> {
|
|
Self::new(version, Self::WASM_NAME, List::WASM_URL).await
|
|
}
|
|
|
|
/// Download the solc binary.
|
|
///
|
|
/// Errors out if the download fails or the digest of the downloaded file
|
|
/// mismatches the expected digest from the release [List].
|
|
pub async fn download(&self) -> anyhow::Result<Vec<u8>> {
|
|
tracing::info!("downloading solc: {self:?}");
|
|
let builds = List::download(self.list).await?.builds;
|
|
let build = builds
|
|
.iter()
|
|
.find(|build| build.version == self.version)
|
|
.ok_or_else(|| anyhow::anyhow!("solc v{} not found builds", self.version))?;
|
|
|
|
let path = build.path.clone();
|
|
let expected_digest = build
|
|
.sha256
|
|
.strip_prefix("0x")
|
|
.unwrap_or(&build.sha256)
|
|
.to_string();
|
|
let url = format!("{}/{}/{}", Self::BASE_URL, self.target, path.display());
|
|
|
|
let file = reqwest::get(url).await?.bytes().await?.to_vec();
|
|
|
|
if hex::encode(Sha256::digest(&file)) != expected_digest {
|
|
anyhow::bail!("sha256 mismatch for solc version {}", self.version);
|
|
}
|
|
|
|
Ok(file)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::{download::SolcDownloader, list::List};
|
|
|
|
#[tokio::test]
|
|
async fn try_get_windows() {
|
|
let version = List::download(List::WINDOWS_URL)
|
|
.await
|
|
.unwrap()
|
|
.latest_release;
|
|
SolcDownloader::windows(version)
|
|
.await
|
|
.unwrap()
|
|
.download()
|
|
.await
|
|
.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn try_get_macosx() {
|
|
let version = List::download(List::MACOSX_URL)
|
|
.await
|
|
.unwrap()
|
|
.latest_release;
|
|
SolcDownloader::macosx(version)
|
|
.await
|
|
.unwrap()
|
|
.download()
|
|
.await
|
|
.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn try_get_linux() {
|
|
let version = List::download(List::LINUX_URL)
|
|
.await
|
|
.unwrap()
|
|
.latest_release;
|
|
SolcDownloader::linux(version)
|
|
.await
|
|
.unwrap()
|
|
.download()
|
|
.await
|
|
.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn try_get_wasm() {
|
|
let version = List::download(List::WASM_URL).await.unwrap().latest_release;
|
|
SolcDownloader::wasm(version)
|
|
.await
|
|
.unwrap()
|
|
.download()
|
|
.await
|
|
.unwrap();
|
|
}
|
|
}
|