Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
92 changes: 92 additions & 0 deletions testing/execution_engine_integration/src/build_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,49 @@ pub fn get_latest_release(repo_dir: &Path, branch_name: &str) -> Result<String,
)
}

/// Gets the latest stable `MAJOR.MINOR.PATCH` tag of the given repo, independent of branches.
///
/// Useful for repos that tag releases on per-release branches rather than a long-lived
/// development branch (where [`get_latest_release`] would not find them via `git describe`).
pub fn get_latest_stable_release(repo_dir: &Path) -> Result<String, String> {
// If the directory was already present it is possible we don't have the most recent tags.
// Fetch them
output_to_result(
Command::new("git")
.arg("fetch")
.arg("--tags")
.arg("--force")
.current_dir(repo_dir)
.output()
.map_err(|e| format!("Failed to fetch tags for {repo_dir:?}: Err: {e}"))?,
|_| {},
)?;
let tags = output_to_result(
Command::new("git")
.arg("tag")
.arg("--list")
.arg("--sort=-v:refname")
.current_dir(repo_dir)
.output()
.map_err(|e| format!("Failed to list tags for {repo_dir:?}: Err: {e}"))?,
|stdout| String::from_utf8_lossy(&stdout).into_owned(),
)?;
tags.lines()
.map(str::trim)
.find(|tag| is_stable_semver(tag))
.map(str::to_string)
.ok_or_else(|| format!("No stable release tag found in {repo_dir:?}"))
}

/// Returns `true` if `tag` looks like a stable `MAJOR.MINOR.PATCH` version.
fn is_stable_semver(tag: &str) -> bool {
let parts: Vec<&str> = tag.split('.').collect();
parts.len() == 3
&& parts
.iter()
.all(|p| !p.is_empty() && p.chars().all(|c| c.is_ascii_digit()))
}

#[allow(dead_code)]
pub fn update_branch(repo_dir: &Path, branch_name: &str) -> Result<(), String> {
output_to_result(
Expand Down Expand Up @@ -136,3 +179,52 @@ pub fn build_stdio() -> Stdio {
Stdio::inherit()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_is_stable_semver_accepts_valid() {
assert!(is_stable_semver("1.37.2"));
assert!(is_stable_semver("0.0.0"));
assert!(is_stable_semver("1.0.0"));
assert!(is_stable_semver("10.20.30"));
assert!(is_stable_semver("100.200.300"));
}

#[test]
fn test_is_stable_semver_rejects_prerelease() {
assert!(!is_stable_semver("1.37.0-rc"));
assert!(!is_stable_semver("1.37.0-rc1"));
assert!(!is_stable_semver("1.37.0-alpha"));
assert!(!is_stable_semver("1.37.0-beta"));
assert!(!is_stable_semver("1.37.0-unstable"));
}

#[test]
fn test_is_stable_semver_rejects_wrong_arity() {
assert!(!is_stable_semver(""));
assert!(!is_stable_semver("1"));
assert!(!is_stable_semver("1.0"));
assert!(!is_stable_semver("1.0.0.0"));
assert!(!is_stable_semver("1.35.2.1"));
}

#[test]
fn test_is_stable_semver_rejects_non_numeric() {
assert!(!is_stable_semver("v1.0.0"));
assert!(!is_stable_semver("1.a.0"));
assert!(!is_stable_semver("abc"));
assert!(!is_stable_semver("1..0"));
assert!(!is_stable_semver(".1.0"));
assert!(!is_stable_semver("1.0."));
}

#[test]
fn test_is_stable_semver_rejects_whitespace() {
assert!(!is_stable_semver(" 1.0.0"));
assert!(!is_stable_semver("1.0.0 "));
assert!(!is_stable_semver("1. 0.0"));
}
}
2 changes: 1 addition & 1 deletion testing/execution_engine_integration/src/genesis_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub fn nethermind_genesis_json() -> Value {
"timestamp": "0x63585F88",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "",
"gasLimit": "0x400000"
"gasLimit": "0x1C9C380"
},
"accounts": {
"0x7b8C3a386C0eea54693fFB0DA17373ffC9228139": {
Expand Down
24 changes: 13 additions & 11 deletions testing/execution_engine_integration/src/nethermind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@ use std::path::{Path, PathBuf};
use std::process::{Child, Command, Output};
use tempfile::TempDir;

/// We've pinned the Nethermind version since our method of using the `master` branch to
/// find the latest tag isn't working. It appears Nethermind don't always tag on `master`.
/// We should fix this so we always pull the latest version of Nethermind.
const NETHERMIND_BRANCH: &str = "release/1.27.0";
const NETHERMIND_REPO_URL: &str = "https://github.com/NethermindEth/nethermind";

fn build_result(repo_dir: &Path) -> Output {
Command::new("dotnet")
.arg("build")
.arg("src/Nethermind/Nethermind.sln")
.arg("src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj")
.arg("-c")
.arg("Release")
.arg("-p:TreatWarningsAsErrors=false")
Expand All @@ -34,8 +30,8 @@ pub fn build(execution_clients_dir: &Path) {
build_utils::clone_repo(execution_clients_dir, NETHERMIND_REPO_URL).unwrap()
}

// Get the latest tag
let last_release = build_utils::get_latest_release(&repo_dir, NETHERMIND_BRANCH).unwrap();
// Get the latest stable release tag
let last_release = build_utils::get_latest_stable_release(&repo_dir).unwrap();
build_utils::checkout(&repo_dir, dbg!(&last_release)).unwrap();

// Build nethermind
Expand Down Expand Up @@ -66,16 +62,22 @@ pub struct NethermindEngine;
impl NethermindEngine {
fn binary_path() -> PathBuf {
let manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
manifest_dir
let nethermind_dir = manifest_dir
.join("execution_clients")
.join("nethermind")
.join("src")
.join("Nethermind")
.join("artifacts")
.join("bin")
.join("Nethermind.Runner")
.join("release")
.join("nethermind")
.join("release");

let latest_path = nethermind_dir.join("net10.0").join("nethermind");
if latest_path.exists() {
latest_path
} else {
nethermind_dir.join("nethermind")
}
}
}

Expand All @@ -102,7 +104,7 @@ impl GenericExecutionEngine for NethermindEngine {
.arg("--datadir")
.arg(datadir.path().to_str().unwrap())
.arg("--config")
.arg("hive")
.arg("none.json")
.arg("--Init.ChainSpecPath")
.arg(genesis_json_path.to_str().unwrap())
.arg("--Merge.TerminalTotalDifficulty")
Expand Down
Loading