mirror of
https://github.com/tig-pool-nk/tig-monorepo.git
synced 2026-02-21 15:31:26 +08:00
Split verification logic into separate crate.
This commit is contained in:
parent
f2e67939c0
commit
0f4cf7ad4c
@ -6,7 +6,7 @@ members = [
|
||||
"tig-protocol",
|
||||
"tig-runtime",
|
||||
"tig-structs",
|
||||
"tig-utils",
|
||||
"tig-utils", "tig-verifier",
|
||||
"tig-worker",
|
||||
]
|
||||
exclude = []
|
||||
|
||||
@ -1,116 +1,75 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::{arg, ArgAction, Command};
|
||||
use libloading::Library;
|
||||
use std::{fs, io::Read, panic, path::PathBuf};
|
||||
use std::{fs, panic, path::PathBuf};
|
||||
use tig_challenges::*;
|
||||
use tig_structs::core::{BenchmarkSettings, OutputData, Solution};
|
||||
use tig_utils::{compress_obj, dejsonify, jsonify};
|
||||
#[cfg(feature = "cuda")]
|
||||
use {
|
||||
cudarc::{
|
||||
driver::{CudaModule, CudaStream, LaunchConfig, PushKernelArg},
|
||||
driver::{CudaContext, CudaModule, CudaStream, LaunchConfig, PushKernelArg},
|
||||
nvrtc::Ptx,
|
||||
runtime::sys::cudaDeviceProp,
|
||||
runtime::{result::device::get_device_prop, sys::cudaDeviceProp},
|
||||
},
|
||||
std::sync::Arc,
|
||||
};
|
||||
|
||||
fn cli() -> Command {
|
||||
Command::new("tig-runtime")
|
||||
.about("Computes or verifies solutions")
|
||||
.about("Executes an algorithm on a single challenge instance")
|
||||
.arg_required_else_help(true)
|
||||
.subcommand(
|
||||
Command::new("compute_solution")
|
||||
.about("Computes a solution")
|
||||
.arg(
|
||||
arg!(<SETTINGS> "Settings json string or path to json file")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
arg!(<RAND_HASH> "A string used in seed generation")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.arg(arg!(<NONCE> "Nonce value").value_parser(clap::value_parser!(u64)))
|
||||
.arg(
|
||||
arg!(<BINARY> "Path to a shared object (*.so) file")
|
||||
.value_parser(clap::value_parser!(PathBuf)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--ptx [PTX] "Path to a CUDA ptx file")
|
||||
.value_parser(clap::value_parser!(PathBuf)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--fuel [FUEL] "Optional maximum fuel parameter")
|
||||
.default_value("2000000000")
|
||||
.value_parser(clap::value_parser!(u64)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--output [OUTPUT_FILE] "If set, the output data will be saved to this file path (default json")
|
||||
.value_parser(clap::value_parser!(PathBuf)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--compress [COMPRESS] "If output file is set, the output data will be compressed as zlib")
|
||||
.action(ArgAction::SetTrue)
|
||||
)
|
||||
.arg(
|
||||
arg!(--gpu [GPU] "Which GPU device to use")
|
||||
.default_value("0")
|
||||
.value_parser(clap::value_parser!(usize)),
|
||||
),
|
||||
.arg(
|
||||
arg!(<SETTINGS> "Settings json string or path to json file")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("verify_solution")
|
||||
.about("Verifies a solution")
|
||||
.arg(
|
||||
arg!(<SETTINGS> "Settings json string or path to json file")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
arg!(<RAND_HASH> "A string used in seed generation")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.arg(arg!(<NONCE> "Nonce value").value_parser(clap::value_parser!(u64)))
|
||||
.arg(
|
||||
arg!(<SOLUTION> "Solution json string, path to json file, or '-' for stdin")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--ptx [PTX] "Path to a CUDA ptx file")
|
||||
.value_parser(clap::value_parser!(PathBuf)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--gpu [GPU] "Which GPU device to use")
|
||||
.default_value("0")
|
||||
.value_parser(clap::value_parser!(usize)),
|
||||
),
|
||||
.arg(
|
||||
arg!(<RAND_HASH> "A string used in seed generation")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.arg(arg!(<NONCE> "Nonce value").value_parser(clap::value_parser!(u64)))
|
||||
.arg(
|
||||
arg!(<BINARY> "Path to a shared object (*.so) file")
|
||||
.value_parser(clap::value_parser!(PathBuf)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--ptx [PTX] "Path to a CUDA ptx file")
|
||||
.value_parser(clap::value_parser!(PathBuf)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--fuel [FUEL] "Optional maximum fuel parameter")
|
||||
.default_value("2000000000")
|
||||
.value_parser(clap::value_parser!(u64)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--output [OUTPUT_FILE] "If set, the output data will be saved to this file path (default json")
|
||||
.value_parser(clap::value_parser!(PathBuf)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--compress [COMPRESS] "If output file is set, the output data will be compressed as zlib")
|
||||
.action(ArgAction::SetTrue)
|
||||
)
|
||||
.arg(
|
||||
arg!(--gpu [GPU] "Which GPU device to use")
|
||||
.default_value("0")
|
||||
.value_parser(clap::value_parser!(usize)),
|
||||
)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let matches = cli().get_matches();
|
||||
|
||||
if let Err(e) = match matches.subcommand() {
|
||||
Some(("compute_solution", sub_m)) => compute_solution(
|
||||
sub_m.get_one::<String>("SETTINGS").unwrap().clone(),
|
||||
sub_m.get_one::<String>("RAND_HASH").unwrap().clone(),
|
||||
*sub_m.get_one::<u64>("NONCE").unwrap(),
|
||||
sub_m.get_one::<PathBuf>("BINARY").unwrap().clone(),
|
||||
sub_m.get_one::<PathBuf>("ptx").cloned(),
|
||||
*sub_m.get_one::<u64>("fuel").unwrap(),
|
||||
sub_m.get_one::<PathBuf>("output").cloned(),
|
||||
sub_m.get_one::<bool>("compress").unwrap().clone(),
|
||||
sub_m.get_one::<usize>("gpu").unwrap().clone(),
|
||||
),
|
||||
Some(("verify_solution", sub_m)) => verify_solution(
|
||||
sub_m.get_one::<String>("SETTINGS").unwrap().clone(),
|
||||
sub_m.get_one::<String>("RAND_HASH").unwrap().clone(),
|
||||
*sub_m.get_one::<u64>("NONCE").unwrap(),
|
||||
sub_m.get_one::<String>("SOLUTION").unwrap().clone(),
|
||||
sub_m.get_one::<PathBuf>("ptx").cloned(),
|
||||
sub_m.get_one::<usize>("gpu").unwrap().clone(),
|
||||
),
|
||||
_ => Err(anyhow!("Invalid subcommand")),
|
||||
} {
|
||||
if let Err(e) = compute_solution(
|
||||
matches.get_one::<String>("SETTINGS").unwrap().clone(),
|
||||
matches.get_one::<String>("RAND_HASH").unwrap().clone(),
|
||||
*matches.get_one::<u64>("NONCE").unwrap(),
|
||||
matches.get_one::<PathBuf>("BINARY").unwrap().clone(),
|
||||
matches.get_one::<PathBuf>("ptx").cloned(),
|
||||
*matches.get_one::<u64>("fuel").unwrap(),
|
||||
matches.get_one::<PathBuf>("output").cloned(),
|
||||
matches.get_one::<bool>("compress").unwrap().clone(),
|
||||
matches.get_one::<usize>("gpu").unwrap().clone(),
|
||||
) {
|
||||
eprintln!("Error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
@ -200,12 +159,12 @@ pub fn compute_solution(
|
||||
let max_fuel_hex = format!("0x{:016x}", max_fuel);
|
||||
let modified_ptx = ptx_content.replace("0xdeadbeefdeadbeef", &max_fuel_hex);
|
||||
|
||||
let ptx = cudarc::nvrtc::Ptx::from_src(modified_ptx);
|
||||
let ctx = cudarc::driver::CudaContext::new(gpu_device).unwrap();
|
||||
let ptx = Ptx::from_src(modified_ptx);
|
||||
let ctx = CudaContext::new(gpu_device).unwrap();
|
||||
ctx.set_blocking_synchronize()?;
|
||||
let module = ctx.load_module(ptx).unwrap();
|
||||
let stream = ctx.default_stream();
|
||||
let prop = cudarc::runtime::result::device::get_device_prop(gpu_device as i32).unwrap();
|
||||
let prop = get_device_prop(gpu_device as i32).unwrap();
|
||||
|
||||
let challenge = $c::Challenge::generate_instance(
|
||||
seed,
|
||||
@ -308,111 +267,6 @@ pub fn compute_solution(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn verify_solution(
|
||||
settings: String,
|
||||
rand_hash: String,
|
||||
nonce: u64,
|
||||
solution_path: String,
|
||||
ptx_path: Option<PathBuf>,
|
||||
gpu_device: usize,
|
||||
) -> Result<()> {
|
||||
let settings = load_settings(&settings);
|
||||
let solution = load_solution(&solution_path);
|
||||
let seed = settings.calc_seed(&rand_hash, nonce);
|
||||
|
||||
let mut err_msg = Option::<String>::None;
|
||||
|
||||
macro_rules! dispatch_challenges {
|
||||
( $( ($c:ident, $cpu_or_gpu:tt) ),+ $(,)? ) => {{
|
||||
match settings.challenge_id.as_str() {
|
||||
$(
|
||||
stringify!($c) => {
|
||||
dispatch_challenges!(@expand $c, $cpu_or_gpu);
|
||||
}
|
||||
)+
|
||||
_ => panic!("Unsupported challenge"),
|
||||
}
|
||||
}};
|
||||
|
||||
(@expand $c:ident, cpu) => {{
|
||||
let challenge = $c::Challenge::generate_instance(
|
||||
seed,
|
||||
&settings.difficulty.into(),
|
||||
).unwrap();
|
||||
|
||||
match $c::Solution::try_from(solution) {
|
||||
Ok(solution) => {
|
||||
match challenge.verify_solution(&solution) {
|
||||
Ok(_) => println!("Solution is valid"),
|
||||
Err(e) => err_msg = Some(format!("Invalid solution: {}", e)),
|
||||
}
|
||||
},
|
||||
Err(_) => err_msg = Some(format!(
|
||||
"Invalid solution. Cannot convert to {}::Solution",
|
||||
stringify!($c)
|
||||
)),
|
||||
}
|
||||
}};
|
||||
|
||||
(@expand $c:ident, gpu) => {{
|
||||
#[cfg(not(feature = "cuda"))]
|
||||
panic!("tig-runtime was not compiled with '--features cuda'");
|
||||
|
||||
#[cfg(feature = "cuda")]
|
||||
{
|
||||
if ptx_path.is_none() {
|
||||
panic!("PTX file is required for GPU challenges.");
|
||||
}
|
||||
|
||||
let ptx_path = ptx_path.unwrap();
|
||||
let ptx_content = std::fs::read_to_string(&ptx_path)
|
||||
.map_err(|e| anyhow!("Failed to read PTX file: {}", e))?;
|
||||
|
||||
let ptx = cudarc::nvrtc::Ptx::from_src(ptx_content);
|
||||
let ctx = cudarc::driver::CudaContext::new(gpu_device).unwrap();
|
||||
ctx.set_blocking_synchronize()?;
|
||||
let module = ctx.load_module(ptx).unwrap();
|
||||
let stream = ctx.default_stream();
|
||||
let prop = cudarc::runtime::result::device::get_device_prop(gpu_device as i32).unwrap();
|
||||
|
||||
let challenge = $c::Challenge::generate_instance(
|
||||
seed,
|
||||
&settings.difficulty.into(),
|
||||
module.clone(),
|
||||
stream.clone(),
|
||||
&prop,
|
||||
).unwrap();
|
||||
|
||||
match $c::Solution::try_from(solution) {
|
||||
Ok(solution) => {
|
||||
match challenge.verify_solution(&solution, module.clone(), stream.clone(), &prop) {
|
||||
Ok(_) => {
|
||||
stream.synchronize()?;
|
||||
ctx.synchronize()?;
|
||||
println!("Solution is valid");
|
||||
},
|
||||
Err(e) => err_msg = Some(format!("Invalid solution: {}", e)),
|
||||
}
|
||||
},
|
||||
Err(_) => err_msg = Some(format!(
|
||||
"Invalid solution. Cannot convert to {}::Solution",
|
||||
stringify!($c)
|
||||
)),
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
dispatch_challenges!((c001, cpu), (c002, cpu), (c003, cpu), (c004, gpu));
|
||||
|
||||
if let Some(err_msg) = err_msg {
|
||||
eprintln!("Verification error: {}", err_msg);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_settings(settings: &str) -> BenchmarkSettings {
|
||||
let settings = if settings.ends_with(".json") {
|
||||
fs::read_to_string(settings).unwrap_or_else(|_| {
|
||||
@ -437,28 +291,3 @@ pub fn load_module(path: &PathBuf) -> Result<Library> {
|
||||
Err(_) => Err(anyhow!("Failed to load module")),
|
||||
}
|
||||
}
|
||||
|
||||
fn load_solution(solution: &str) -> Solution {
|
||||
let solution = if solution == "-" {
|
||||
let mut buffer = String::new();
|
||||
std::io::stdin()
|
||||
.read_to_string(&mut buffer)
|
||||
.unwrap_or_else(|_| {
|
||||
eprintln!("Failed to read solution from stdin");
|
||||
std::process::exit(1);
|
||||
});
|
||||
buffer
|
||||
} else if solution.ends_with(".json") {
|
||||
fs::read_to_string(&solution).unwrap_or_else(|_| {
|
||||
eprintln!("Failed to read solution file: {}", solution);
|
||||
std::process::exit(1);
|
||||
})
|
||||
} else {
|
||||
solution.to_string()
|
||||
};
|
||||
|
||||
dejsonify::<Solution>(&solution).unwrap_or_else(|_| {
|
||||
eprintln!("Failed to parse solution");
|
||||
std::process::exit(1);
|
||||
})
|
||||
}
|
||||
|
||||
22
tig-verifier/Cargo.toml
Normal file
22
tig-verifier/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "tig-verifier"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
readme.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.81"
|
||||
clap = { version = "4.5.4" }
|
||||
cudarc = { version = "0.16.2", features = [
|
||||
"cuda-version-from-build-system",
|
||||
], optional = true }
|
||||
serde = { version = "1.0.196", features = ["derive"] }
|
||||
serde_json = { version = "1.0.113" }
|
||||
tig-challenges = { path = "../tig-challenges" }
|
||||
tig-structs = { path = "../tig-structs" }
|
||||
tig-utils = { path = "../tig-utils" }
|
||||
|
||||
[features]
|
||||
cuda = ["cudarc", "tig-challenges/cuda"]
|
||||
220
tig-verifier/src/main.rs
Normal file
220
tig-verifier/src/main.rs
Normal file
@ -0,0 +1,220 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::{arg, Command};
|
||||
use std::{fs, io::Read, panic, path::PathBuf};
|
||||
use tig_challenges::*;
|
||||
use tig_structs::core::{BenchmarkSettings, Solution};
|
||||
use tig_utils::dejsonify;
|
||||
|
||||
#[cfg(feature = "cuda")]
|
||||
use cudarc::{driver::CudaContext, nvrtc::Ptx, runtime::result::device::get_device_prop};
|
||||
|
||||
fn cli() -> Command {
|
||||
Command::new("tig-verifier")
|
||||
.about("Verifies a solution or merkle proof")
|
||||
.arg_required_else_help(true)
|
||||
.subcommand(
|
||||
Command::new("verify_solution")
|
||||
.about("Verifies a solution")
|
||||
.arg(
|
||||
arg!(<SETTINGS> "Settings json string or path to json file")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
arg!(<RAND_HASH> "A string used in seed generation")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.arg(arg!(<NONCE> "Nonce value").value_parser(clap::value_parser!(u64)))
|
||||
.arg(
|
||||
arg!(<SOLUTION> "Solution json string, path to json file, or '-' for stdin")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--ptx [PTX] "Path to a CUDA ptx file")
|
||||
.value_parser(clap::value_parser!(PathBuf)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--gpu [GPU] "Which GPU device to use")
|
||||
.default_value("0")
|
||||
.value_parser(clap::value_parser!(usize)),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("verify_merkle_proof")
|
||||
.about("Verifies a merkle proof")
|
||||
.arg(arg!(<ROOT> "Merkle root").value_parser(clap::value_parser!(String)))
|
||||
.arg(
|
||||
arg!(<PROOF> "Merkle proof json string, path to json file, or '-' for stdin")
|
||||
.value_parser(clap::value_parser!(String)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let matches = cli().get_matches();
|
||||
|
||||
if let Err(e) = match matches.subcommand() {
|
||||
Some(("verify_solution", sub_m)) => verify_solution(
|
||||
sub_m.get_one::<String>("SETTINGS").unwrap().clone(),
|
||||
sub_m.get_one::<String>("RAND_HASH").unwrap().clone(),
|
||||
*sub_m.get_one::<u64>("NONCE").unwrap(),
|
||||
sub_m.get_one::<String>("SOLUTION").unwrap().clone(),
|
||||
sub_m.get_one::<PathBuf>("ptx").cloned(),
|
||||
sub_m.get_one::<usize>("gpu").unwrap().clone(),
|
||||
),
|
||||
Some(("verify_merkle_proof", sub_m)) => verify_merkle_proof(
|
||||
sub_m.get_one::<String>("ROOT").unwrap().clone(),
|
||||
sub_m.get_one::<String>("PROOF").unwrap().clone(),
|
||||
),
|
||||
_ => Err(anyhow!("Invalid subcommand")),
|
||||
} {
|
||||
eprintln!("Error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_solution(
|
||||
settings: String,
|
||||
rand_hash: String,
|
||||
nonce: u64,
|
||||
solution_path: String,
|
||||
ptx_path: Option<PathBuf>,
|
||||
gpu_device: usize,
|
||||
) -> Result<()> {
|
||||
let settings = load_settings(&settings);
|
||||
let solution = load_solution(&solution_path);
|
||||
let seed = settings.calc_seed(&rand_hash, nonce);
|
||||
|
||||
let mut err_msg = Option::<String>::None;
|
||||
|
||||
macro_rules! dispatch_challenges {
|
||||
( $( ($c:ident, $cpu_or_gpu:tt) ),+ $(,)? ) => {{
|
||||
match settings.challenge_id.as_str() {
|
||||
$(
|
||||
stringify!($c) => {
|
||||
dispatch_challenges!(@expand $c, $cpu_or_gpu);
|
||||
}
|
||||
)+
|
||||
_ => panic!("Unsupported challenge"),
|
||||
}
|
||||
}};
|
||||
|
||||
(@expand $c:ident, cpu) => {{
|
||||
let challenge = $c::Challenge::generate_instance(
|
||||
seed,
|
||||
&settings.difficulty.into(),
|
||||
).unwrap();
|
||||
|
||||
match $c::Solution::try_from(solution) {
|
||||
Ok(solution) => {
|
||||
match challenge.verify_solution(&solution) {
|
||||
Ok(_) => println!("Solution is valid"),
|
||||
Err(e) => err_msg = Some(format!("Invalid solution: {}", e)),
|
||||
}
|
||||
},
|
||||
Err(_) => err_msg = Some(format!(
|
||||
"Invalid solution. Cannot convert to {}::Solution",
|
||||
stringify!($c)
|
||||
)),
|
||||
}
|
||||
}};
|
||||
|
||||
(@expand $c:ident, gpu) => {{
|
||||
#[cfg(not(feature = "cuda"))]
|
||||
panic!("tig-runtime was not compiled with '--features cuda'");
|
||||
|
||||
#[cfg(feature = "cuda")]
|
||||
{
|
||||
if ptx_path.is_none() {
|
||||
panic!("PTX file is required for GPU challenges.");
|
||||
}
|
||||
|
||||
let ptx = Ptx::from_file(ptx_path.unwrap());
|
||||
let ctx = CudaContext::new(gpu_device).unwrap();
|
||||
ctx.set_blocking_synchronize()?;
|
||||
let module = ctx.load_module(ptx).unwrap();
|
||||
let stream = ctx.default_stream();
|
||||
let prop = get_device_prop(gpu_device as i32).unwrap();
|
||||
|
||||
let challenge = $c::Challenge::generate_instance(
|
||||
seed,
|
||||
&settings.difficulty.into(),
|
||||
module.clone(),
|
||||
stream.clone(),
|
||||
&prop,
|
||||
).unwrap();
|
||||
|
||||
match $c::Solution::try_from(solution) {
|
||||
Ok(solution) => {
|
||||
match challenge.verify_solution(&solution, module.clone(), stream.clone(), &prop) {
|
||||
Ok(_) => {
|
||||
stream.synchronize()?;
|
||||
ctx.synchronize()?;
|
||||
println!("Solution is valid");
|
||||
},
|
||||
Err(e) => err_msg = Some(format!("Invalid solution: {}", e)),
|
||||
}
|
||||
},
|
||||
Err(_) => err_msg = Some(format!(
|
||||
"Invalid solution. Cannot convert to {}::Solution",
|
||||
stringify!($c)
|
||||
)),
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
dispatch_challenges!((c001, cpu), (c002, cpu), (c003, cpu), (c004, gpu));
|
||||
|
||||
if let Some(err_msg) = err_msg {
|
||||
eprintln!("Verification error: {}", err_msg);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn verify_merkle_proof(_merkle_root: String, _merkle_proof: String) -> Result<()> {
|
||||
// TODO
|
||||
Err(anyhow!("Merkle proof verification is not implemented yet"))
|
||||
}
|
||||
|
||||
fn load_settings(settings: &str) -> BenchmarkSettings {
|
||||
let settings = if settings.ends_with(".json") {
|
||||
fs::read_to_string(settings).unwrap_or_else(|_| {
|
||||
eprintln!("Failed to read settings file: {}", settings);
|
||||
std::process::exit(1);
|
||||
})
|
||||
} else {
|
||||
settings.to_string()
|
||||
};
|
||||
|
||||
dejsonify::<BenchmarkSettings>(&settings).unwrap_or_else(|_| {
|
||||
eprintln!("Failed to parse settings");
|
||||
std::process::exit(1);
|
||||
})
|
||||
}
|
||||
|
||||
fn load_solution(solution: &str) -> Solution {
|
||||
let solution = if solution == "-" {
|
||||
let mut buffer = String::new();
|
||||
std::io::stdin()
|
||||
.read_to_string(&mut buffer)
|
||||
.unwrap_or_else(|_| {
|
||||
eprintln!("Failed to read solution from stdin");
|
||||
std::process::exit(1);
|
||||
});
|
||||
buffer
|
||||
} else if solution.ends_with(".json") {
|
||||
fs::read_to_string(&solution).unwrap_or_else(|_| {
|
||||
eprintln!("Failed to read solution file: {}", solution);
|
||||
std::process::exit(1);
|
||||
})
|
||||
} else {
|
||||
solution.to_string()
|
||||
};
|
||||
|
||||
dejsonify::<Solution>(&solution).unwrap_or_else(|_| {
|
||||
eprintln!("Failed to parse solution");
|
||||
std::process::exit(1);
|
||||
})
|
||||
}
|
||||
@ -148,8 +148,7 @@ fn compute_batch(
|
||||
tokio::spawn(async move {
|
||||
let temp_file = NamedTempFile::new()?;
|
||||
let mut cmd = std::process::Command::new(runtime_path);
|
||||
cmd.arg("compute_solution")
|
||||
.arg(settings)
|
||||
cmd.arg(settings)
|
||||
.arg(rand_hash)
|
||||
.arg(nonce.to_string())
|
||||
.arg(binary_path)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user