Skip to content

Commit 46521d9

Browse files
authored
Use Official linux-arm64 Binaries (#182)
This changes how 64-bit ARM Linux (the `linux-aarch64` platform) versions are handled to use the official Solidity binaries. Since `v0.8.31`, Solidity officially releases [`linux-arm64`](https://binaries.soliditylang.org/linux-arm64/list.json) binaries. Note a few small details: 1. Solidity calls the platform `linux-arm64`, while SVM calls it `linux-aarch64`. I assumed that changing the naming to match Solidity would be a much larger breaking change, so I decided to have the `releases::all_releases` handle the naming discrepancy. 2. Some small adjustments were required for the `linux_aarch64` install test as it wasn't compiling. 3. The binary list from `nikitastupin/solc` does not correctly add `prerelease` information to the `builds` field; so in order to differentiate between `v0.8.31` (from the official releases) and `v0.8.31-pre.1` (from the `nikitastupin/solc` releases) some additional "fixup" code was added. Right now, the generated `svm-builds` constants for `linux-aarch64` don't correctly include `-pre.1` prerelease information.
1 parent 99fe67b commit 46521d9

File tree

2 files changed

+142
-31
lines changed

2 files changed

+142
-31
lines changed

crates/svm-rs/src/install.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ mod tests {
304304
use rand::seq::IndexedRandom;
305305

306306
#[allow(unused)]
307-
const LATEST: Version = Version::new(0, 8, 30);
307+
const LATEST: Version = Version::new(0, 8, 33);
308308

309309
#[tokio::test]
310310
#[serial_test::serial]
@@ -450,15 +450,17 @@ mod tests {
450450
);
451451
}
452452

453-
// ensures we can download the latest native solc for linux aarch64
453+
// Ensures we can download the latest native solc for linux-aarch64.
454454
#[tokio::test(flavor = "multi_thread")]
455455
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
456-
async fn can_download_latest_linux_aarch64() {
457-
let artifacts = all_releases(Platform::LinuxAarch64).await.unwrap();
456+
async fn can_download_linux_aarch64_latest() {
457+
let artifacts = all_releases(platform::Platform::LinuxAarch64)
458+
.await
459+
.unwrap();
458460

459461
let artifact = artifacts.releases.get(&LATEST).unwrap();
460462
let download_url = artifact_url(
461-
Platform::LinuxAarch64,
463+
platform::Platform::LinuxAarch64,
462464
&LATEST,
463465
artifact.to_string().as_str(),
464466
)
@@ -469,7 +471,33 @@ mod tests {
469471
let resp = reqwest::get(download_url).await.unwrap();
470472
assert!(resp.status().is_success());
471473
let binbytes = resp.bytes().await.unwrap();
472-
ensure_checksum(&binbytes, &LATEST, checksum).unwrap();
474+
ensure_checksum(&binbytes, &LATEST, &checksum).unwrap();
475+
}
476+
477+
// Ensures we can download thirdparty linux-aarch64 solc binaries that do not have official
478+
// Solidity binary releases.
479+
#[tokio::test(flavor = "multi_thread")]
480+
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
481+
async fn can_download_linux_aarch64_thirdparty() {
482+
let version: Version = "0.8.30".parse().unwrap();
483+
let artifacts = all_releases(platform::Platform::LinuxAarch64)
484+
.await
485+
.unwrap();
486+
487+
let artifact = artifacts.releases.get(&version).unwrap();
488+
let download_url = artifact_url(
489+
platform::Platform::LinuxAarch64,
490+
&version,
491+
artifact.to_string().as_str(),
492+
)
493+
.unwrap();
494+
495+
let checksum = artifacts.get_checksum(&version).unwrap();
496+
497+
let resp = reqwest::get(download_url).await.unwrap();
498+
assert!(resp.status().is_success());
499+
let binbytes = resp.bytes().await.unwrap();
500+
ensure_checksum(&binbytes, &version, &checksum).unwrap();
473501
}
474502

475503
#[tokio::test]

crates/svm-rs/src/releases.rs

Lines changed: 108 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ static OLD_SOLC_RELEASES: LazyLock<Releases> = LazyLock::new(|| {
3030

3131
const LINUX_AARCH64_MIN: Version = Version::new(0, 5, 0);
3232

33+
// NOTE: Since version 0.8.31, Linux aarch64 releases are available: https://binaries.soliditylang.org/linux-arm64/list.json
34+
const LINUX_AARCH64_BINARIES: Version = Version::new(0, 8, 31);
35+
36+
// NOTE: The official Solidity releases uses the platform name "linux-arm64"
37+
// instead of the "linux-aarch64" naming which is used by SVM.
38+
static LINUX_AARCH64_PLATFORM: &str = "linux-arm64";
39+
3340
static LINUX_AARCH64_URL_PREFIX: &str = "https://raw.githubusercontent.com/nikitastupin/solc/2287d4326237172acf91ce42fd7ec18a67b7f512/linux/aarch64";
3441

3542
static LINUX_AARCH64_RELEASES_URL: &str = "https://raw.githubusercontent.com/nikitastupin/solc/2287d4326237172acf91ce42fd7ec18a67b7f512/linux/aarch64/list.json";
@@ -120,6 +127,18 @@ impl Releases {
120127
versions.sort_unstable();
121128
versions
122129
}
130+
131+
/// Retain versions matching a predicate.
132+
fn retain_versions(&mut self, mut pred: impl FnMut(&Version) -> bool) {
133+
self.builds.retain(|build| pred(&build.version));
134+
self.releases.retain(|version, _| pred(version));
135+
}
136+
137+
/// Extends releases with another.
138+
fn extend(&mut self, other: Self) {
139+
self.builds.extend(other.builds);
140+
self.releases.extend(other.releases);
141+
}
123142
}
124143

125144
/// Build info contains the SHA256 checksum of a solc binary.
@@ -158,7 +177,22 @@ mod hex_string {
158177
pub fn blocking_all_releases(platform: Platform) -> Result<Releases, SvmError> {
159178
match platform {
160179
Platform::LinuxAarch64 => {
161-
Ok(reqwest::blocking::get(LINUX_AARCH64_RELEASES_URL)?.json::<Releases>()?)
180+
// Prior to version 0.8.31, releases for Linux arm64 builds was provided by the
181+
// `nikitastupin/solc` repository. From 0.8.31 (inclusive) and onwards, official
182+
// binary releases are provided by the Solidity project.
183+
let mut releases =
184+
reqwest::blocking::get(LINUX_AARCH64_RELEASES_URL)?.json::<Releases>()?;
185+
releases.retain_versions(|v| *v < LINUX_AARCH64_BINARIES);
186+
fix_build_prerelease(&mut releases);
187+
let mut official = reqwest::blocking::get(format!(
188+
"{SOLC_RELEASES_URL}/{LINUX_AARCH64_PLATFORM}/list.json",
189+
))?
190+
.json::<Releases>()?;
191+
// Filtering older releases isn't strinctly necessary here, but do it just in case
192+
// Solidity retroactively starts adding older release binaries for linux-aarch64.
193+
official.retain_versions(|v| *v >= LINUX_AARCH64_BINARIES);
194+
releases.extend(official);
195+
Ok(releases)
162196
}
163197
Platform::MacOsAarch64 => {
164198
// The supported versions for both macos-amd64 and macos-aarch64 are the same.
@@ -170,23 +204,16 @@ pub fn blocking_all_releases(platform: Platform) -> Result<Releases, SvmError> {
170204
// require Rosetta support.
171205
//
172206
// Note: Since 0.8.24 universal macosx releases are available
173-
let mut native =
174-
reqwest::blocking::get(MACOS_AARCH64_RELEASES_URL)?.json::<Releases>()?;
207+
let native = reqwest::blocking::get(MACOS_AARCH64_RELEASES_URL)?.json::<Releases>()?;
175208
let mut releases = reqwest::blocking::get(format!(
176209
"{}/{}/list.json",
177210
SOLC_RELEASES_URL,
178211
Platform::MacOsAmd64,
179212
))?
180213
.json::<Releases>()?;
181-
releases.builds.retain(|b| {
182-
b.version < MACOS_AARCH64_NATIVE || b.version > UNIVERSAL_MACOS_BINARIES
183-
});
184214
releases
185-
.releases
186-
.retain(|v, _| *v < MACOS_AARCH64_NATIVE || *v > UNIVERSAL_MACOS_BINARIES);
187-
releases.builds.extend_from_slice(&native.builds);
188-
189-
releases.releases.append(&mut native.releases);
215+
.retain_versions(|v| *v < MACOS_AARCH64_NATIVE || *v > UNIVERSAL_MACOS_BINARIES);
216+
releases.extend(native);
190217
Ok(releases)
191218
}
192219
Platform::AndroidAarch64 => {
@@ -214,10 +241,28 @@ pub fn blocking_all_releases(platform: Platform) -> Result<Releases, SvmError> {
214241
/// Fetch all releases available for the provided platform.
215242
pub async fn all_releases(platform: Platform) -> Result<Releases, SvmError> {
216243
match platform {
217-
Platform::LinuxAarch64 => Ok(get(LINUX_AARCH64_RELEASES_URL)
244+
Platform::LinuxAarch64 => {
245+
// Prior to version 0.8.31, releases for Linux arm64 builds was provided by the
246+
// `nikitastupin/solc` repository. From 0.8.31 (inclusive) and onwards, official
247+
// binary releases are provided by the Solidity project.
248+
let mut releases = get(LINUX_AARCH64_RELEASES_URL)
249+
.await?
250+
.json::<Releases>()
251+
.await?;
252+
releases.retain_versions(|v| *v < LINUX_AARCH64_BINARIES);
253+
fix_build_prerelease(&mut releases);
254+
let mut official = get(format!(
255+
"{SOLC_RELEASES_URL}/{LINUX_AARCH64_PLATFORM}/list.json",
256+
))
218257
.await?
219258
.json::<Releases>()
220-
.await?),
259+
.await?;
260+
// Filtering older releases isn't strinctly necessary here, but do it just in case
261+
// Solidity retroactively starts adding older release binaries for linux-aarch64.
262+
official.retain_versions(|v| *v >= LINUX_AARCH64_BINARIES);
263+
releases.extend(official);
264+
Ok(releases)
265+
}
221266
Platform::MacOsAarch64 => {
222267
// The supported versions for both macos-amd64 and macos-aarch64 are the same.
223268
//
@@ -226,7 +271,7 @@ pub async fn all_releases(platform: Platform) -> Result<Releases, SvmError> {
226271
//
227272
// 2. For version <= 0.8.4 we fetch releases from https://binaries.soliditylang.org and
228273
// require Rosetta support.
229-
let mut native = get(MACOS_AARCH64_RELEASES_URL)
274+
let native = get(MACOS_AARCH64_RELEASES_URL)
230275
.await?
231276
.json::<Releases>()
232277
.await?;
@@ -238,15 +283,10 @@ pub async fn all_releases(platform: Platform) -> Result<Releases, SvmError> {
238283
.await?
239284
.json::<Releases>()
240285
.await?;
241-
releases.builds.retain(|b| {
242-
b.version < MACOS_AARCH64_NATIVE || b.version > UNIVERSAL_MACOS_BINARIES
243-
});
244286
releases
245-
.releases
246-
.retain(|v, _| *v < MACOS_AARCH64_NATIVE || *v > UNIVERSAL_MACOS_BINARIES);
287+
.retain_versions(|v| *v < MACOS_AARCH64_NATIVE || *v > UNIVERSAL_MACOS_BINARIES);
247288

248-
releases.builds.extend_from_slice(&native.builds);
249-
releases.releases.append(&mut native.releases);
289+
releases.extend(native);
250290
Ok(releases)
251291
}
252292
Platform::AndroidAarch64 => Ok(get(ANDROID_AARCH64_RELEASES_URL)
@@ -281,14 +321,27 @@ pub async fn all_releases(platform: Platform) -> Result<Releases, SvmError> {
281321
fn unified_releases(releases: Releases, platform: Platform) -> Releases {
282322
if platform == Platform::LinuxAmd64 {
283323
let mut all_releases = OLD_SOLC_RELEASES.clone();
284-
all_releases.builds.extend(releases.builds);
285-
all_releases.releases.extend(releases.releases);
324+
all_releases.extend(releases);
286325
all_releases
287326
} else {
288327
releases
289328
}
290329
}
291330

331+
/// Fixes build pre-release info for certain release lists.
332+
///
333+
/// In particular, the release list from the `nikitastupin/solc` repository does correctly label
334+
/// `prerelease` information in the build array, so populate it based on the `version`.
335+
fn fix_build_prerelease(releases: &mut Releases) {
336+
for build in &mut releases.builds {
337+
build.prerelease = if build.version.pre.is_empty() {
338+
None
339+
} else {
340+
Some(build.version.pre.as_str().to_owned())
341+
};
342+
}
343+
}
344+
292345
/// Construct the URL to the Solc binary for the specified release version and target platform.
293346
pub(crate) fn artifact_url(
294347
platform: Platform,
@@ -305,7 +358,11 @@ pub(crate) fn artifact_url(
305358
}
306359

307360
if platform == Platform::LinuxAarch64 {
308-
if *version >= LINUX_AARCH64_MIN {
361+
if *version >= LINUX_AARCH64_BINARIES {
362+
return Ok(Url::parse(&format!(
363+
"{SOLC_RELEASES_URL}/{LINUX_AARCH64_PLATFORM}/{artifact}"
364+
))?);
365+
} else if *version >= LINUX_AARCH64_MIN {
309366
return Ok(Url::parse(&format!(
310367
"{LINUX_AARCH64_URL_PREFIX}/{artifact}"
311368
))?);
@@ -431,7 +488,33 @@ mod tests {
431488

432489
#[tokio::test]
433490
async fn test_all_releases_linux_aarch64() {
434-
assert!(all_releases(Platform::LinuxAarch64).await.is_ok());
491+
let releases = all_releases(Platform::LinuxAarch64)
492+
.await
493+
.expect("could not fetch releases for linux-aarch64");
494+
let thirdparty = LINUX_AARCH64_MIN;
495+
let url1 = artifact_url(
496+
Platform::LinuxAarch64,
497+
&thirdparty,
498+
releases.get_artifact(&thirdparty).unwrap(),
499+
)
500+
.expect("could not fetch artifact URL");
501+
let prerelease = Version::parse("0.8.31-pre.1").expect("failed to parse version");
502+
let url2 = artifact_url(
503+
Platform::LinuxAarch64,
504+
&prerelease,
505+
releases.get_artifact(&prerelease).unwrap(),
506+
)
507+
.expect("could not fetch artifact URL");
508+
let official = LINUX_AARCH64_BINARIES;
509+
let url3 = artifact_url(
510+
Platform::LinuxAarch64,
511+
&official,
512+
releases.get_artifact(&official).unwrap(),
513+
)
514+
.expect("could not fetch artifact URL");
515+
assert!(url1.to_string().contains(LINUX_AARCH64_URL_PREFIX));
516+
assert!(url2.to_string().contains(LINUX_AARCH64_URL_PREFIX));
517+
assert!(url3.to_string().contains(SOLC_RELEASES_URL));
435518
}
436519

437520
#[tokio::test]

0 commit comments

Comments
 (0)