pub use crate::{
host::{EXECUTE_BINARY_NAME, PREPARE_BINARY_NAME},
worker_interface::{spawn_with_program_path, SpawnErr},
};
use crate::{artifacts::ArtifactId, get_worker_version};
use is_executable::IsExecutable;
use polkadot_node_core_pvf_common::pvf::PvfPrepData;
use polkadot_node_primitives::NODE_VERSION;
use polkadot_primitives::ExecutorParams;
use std::{
path::PathBuf,
sync::{Mutex, OnceLock},
};
pub fn validate_candidate(
code: &[u8],
params: &[u8],
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
use polkadot_node_core_pvf_common::executor_interface::{prepare, prevalidate};
use polkadot_node_core_pvf_execute_worker::execute_artifact;
let code = sp_maybe_compressed_blob::decompress(code, 10 * 1024 * 1024)
.expect("Decompressing code failed");
let blob = prevalidate(&code)?;
let executor_params = ExecutorParams::default();
let compiled_artifact_blob = prepare(blob, &executor_params)?;
let result = unsafe {
execute_artifact(&compiled_artifact_blob, &executor_params, params)?
};
Ok(result)
}
pub fn build_workers_and_get_paths() -> (PathBuf, PathBuf) {
static WORKER_PATHS: OnceLock<Mutex<(PathBuf, PathBuf)>> = OnceLock::new();
fn build_workers() {
let mut build_args = vec![
"build",
"--package=polkadot",
"--bin=polkadot-prepare-worker",
"--bin=polkadot-execute-worker",
];
if cfg!(build_profile = "release") {
build_args.push("--release");
}
let mut cargo = std::process::Command::new("cargo");
let cmd = cargo
.env("SKIP_WASM_BUILD", "1")
.args(build_args)
.stdout(std::process::Stdio::piped());
println!("INFO: calling `{cmd:?}`");
let exit_status = cmd.status().expect("Failed to run the build program");
if !exit_status.success() {
eprintln!("ERROR: Failed to build workers: {}", exit_status.code().unwrap());
std::process::exit(1);
}
}
let mutex = WORKER_PATHS.get_or_init(|| {
let mut workers_path = std::env::current_exe().unwrap();
workers_path.pop();
workers_path.pop();
let mut prepare_worker_path = workers_path.clone();
prepare_worker_path.push(PREPARE_BINARY_NAME);
let mut execute_worker_path = workers_path.clone();
execute_worker_path.push(EXECUTE_BINARY_NAME);
if !prepare_worker_path.is_executable() {
println!("WARN: Prepare worker does not exist or is not executable. Workers directory: {:?}", workers_path);
}
if !execute_worker_path.is_executable() {
println!("WARN: Execute worker does not exist or is not executable. Workers directory: {:?}", workers_path);
}
if let Ok(ver) = get_worker_version(&prepare_worker_path) {
if ver != NODE_VERSION {
println!("WARN: Prepare worker version {ver} does not match node version {NODE_VERSION}; worker path: {prepare_worker_path:?}");
}
}
if let Ok(ver) = get_worker_version(&execute_worker_path) {
if ver != NODE_VERSION {
println!("WARN: Execute worker version {ver} does not match node version {NODE_VERSION}; worker path: {execute_worker_path:?}");
}
}
build_workers();
Mutex::new((prepare_worker_path, execute_worker_path))
});
let guard = mutex.lock().unwrap();
(guard.0.clone(), guard.1.clone())
}
pub fn artifact_id(discriminator: u32) -> ArtifactId {
ArtifactId::from_pvf_prep_data(&PvfPrepData::from_discriminator(discriminator))
}