Forwardport: Validation: don't detect STDIN closing when running in process (#1695) (#1703)

* Initial commit

Forked at: 8b59544660
Parent branch: origin/master

* Validation: don't detect STDIN closing when running in process  (#1695)
This commit is contained in:
Cecile Tonglet
2020-09-11 14:41:31 +02:00
committed by GitHub
parent 8b59544660
commit 84f2ab3d7f
5 changed files with 137 additions and 124 deletions
@@ -37,7 +37,7 @@ use polkadot_primitives::v1::{
}; };
use polkadot_parachain::wasm_executor::{ use polkadot_parachain::wasm_executor::{
self, ValidationPool, ExecutionMode, ValidationError, self, ValidationPool, ExecutionMode, ValidationError,
InvalidCandidate as WasmInvalidCandidate, ValidationExecutionMode, InvalidCandidate as WasmInvalidCandidate,
}; };
use polkadot_parachain::primitives::{ValidationResult as WasmValidationResult, ValidationParams}; use polkadot_parachain::primitives::{ValidationResult as WasmValidationResult, ValidationParams};
@@ -130,7 +130,7 @@ async fn run(
) )
-> SubsystemResult<()> -> SubsystemResult<()>
{ {
let pool = ValidationPool::new(ValidationExecutionMode::ExternalProcessSelfHost); let execution_mode = ExecutionMode::ExternalProcessSelfHost(ValidationPool::new());
loop { loop {
match ctx.recv().await? { match ctx.recv().await? {
@@ -145,7 +145,7 @@ async fn run(
) => { ) => {
let res = spawn_validate_from_chain_state( let res = spawn_validate_from_chain_state(
&mut ctx, &mut ctx,
Some(pool.clone()), execution_mode.clone(),
descriptor, descriptor,
pov, pov,
spawn.clone(), spawn.clone(),
@@ -169,7 +169,7 @@ async fn run(
) => { ) => {
let res = spawn_validate_exhaustive( let res = spawn_validate_exhaustive(
&mut ctx, &mut ctx,
Some(pool.clone()), execution_mode.clone(),
persisted_validation_data, persisted_validation_data,
transient_validation_data, transient_validation_data,
validation_code, validation_code,
@@ -271,7 +271,7 @@ async fn check_assumption_validation_data(
async fn spawn_validate_from_chain_state( async fn spawn_validate_from_chain_state(
ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>, ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>,
validation_pool: Option<ValidationPool>, execution_mode: ExecutionMode,
descriptor: CandidateDescriptor, descriptor: CandidateDescriptor,
pov: Arc<PoV>, pov: Arc<PoV>,
spawn: impl SpawnNamed + 'static, spawn: impl SpawnNamed + 'static,
@@ -288,7 +288,7 @@ async fn spawn_validate_from_chain_state(
AssumptionCheckOutcome::Matches(validation_data, validation_code) => { AssumptionCheckOutcome::Matches(validation_data, validation_code) => {
return spawn_validate_exhaustive( return spawn_validate_exhaustive(
ctx, ctx,
validation_pool, execution_mode,
validation_data.persisted, validation_data.persisted,
Some(validation_data.transient), Some(validation_data.transient),
validation_code, validation_code,
@@ -309,7 +309,7 @@ async fn spawn_validate_from_chain_state(
AssumptionCheckOutcome::Matches(validation_data, validation_code) => { AssumptionCheckOutcome::Matches(validation_data, validation_code) => {
return spawn_validate_exhaustive( return spawn_validate_exhaustive(
ctx, ctx,
validation_pool, execution_mode,
validation_data.persisted, validation_data.persisted,
Some(validation_data.transient), Some(validation_data.transient),
validation_code, validation_code,
@@ -330,7 +330,7 @@ async fn spawn_validate_from_chain_state(
async fn spawn_validate_exhaustive( async fn spawn_validate_exhaustive(
ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>, ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>,
validation_pool: Option<ValidationPool>, execution_mode: ExecutionMode,
persisted_validation_data: PersistedValidationData, persisted_validation_data: PersistedValidationData,
transient_validation_data: Option<TransientValidationData>, transient_validation_data: Option<TransientValidationData>,
validation_code: ValidationCode, validation_code: ValidationCode,
@@ -341,7 +341,7 @@ async fn spawn_validate_exhaustive(
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let fut = async move { let fut = async move {
let res = validate_candidate_exhaustive::<RealValidationBackend, _>( let res = validate_candidate_exhaustive::<RealValidationBackend, _>(
validation_pool, execution_mode,
persisted_validation_data, persisted_validation_data,
transient_validation_data, transient_validation_data,
validation_code, validation_code,
@@ -422,22 +422,18 @@ trait ValidationBackend {
struct RealValidationBackend; struct RealValidationBackend;
impl ValidationBackend for RealValidationBackend { impl ValidationBackend for RealValidationBackend {
type Arg = Option<ValidationPool>; type Arg = ExecutionMode;
fn validate<S: SpawnNamed + 'static>( fn validate<S: SpawnNamed + 'static>(
pool: Option<ValidationPool>, execution_mode: ExecutionMode,
validation_code: &ValidationCode, validation_code: &ValidationCode,
params: ValidationParams, params: ValidationParams,
spawn: S, spawn: S,
) -> Result<WasmValidationResult, ValidationError> { ) -> Result<WasmValidationResult, ValidationError> {
let execution_mode = pool.as_ref()
.map(ExecutionMode::Remote)
.unwrap_or(ExecutionMode::Local);
wasm_executor::validate_candidate( wasm_executor::validate_candidate(
&validation_code.0, &validation_code.0,
params, params,
execution_mode, &execution_mode,
spawn, spawn,
) )
} }
+33 -15
View File
@@ -20,7 +20,7 @@
//! Assuming the parameters are correct, this module provides a wrapper around //! Assuming the parameters are correct, this module provides a wrapper around
//! a WASM VM for re-execution of a parachain candidate. //! a WASM VM for re-execution of a parachain candidate.
use std::any::{TypeId, Any}; use std::{any::{TypeId, Any}, path::PathBuf};
use crate::primitives::{ValidationParams, ValidationResult}; use crate::primitives::{ValidationParams, ValidationResult};
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use sp_core::{storage::{ChildInfo, TrackedStorageKey}, traits::{CallInWasm, SpawnNamed}}; use sp_core::{storage::{ChildInfo, TrackedStorageKey}, traits::{CallInWasm, SpawnNamed}};
@@ -28,7 +28,7 @@ use sp_externalities::Extensions;
use sp_wasm_interface::HostFunctions as _; use sp_wasm_interface::HostFunctions as _;
#[cfg(not(any(target_os = "android", target_os = "unknown")))] #[cfg(not(any(target_os = "android", target_os = "unknown")))]
pub use validation_host::{run_worker, ValidationPool, EXECUTION_TIMEOUT_SEC, ValidationExecutionMode}; pub use validation_host::{run_worker, ValidationPool, EXECUTION_TIMEOUT_SEC, WORKER_ARGS};
mod validation_host; mod validation_host;
@@ -58,16 +58,29 @@ pub fn run_worker(_: &str) -> Result<(), String> {
Err("Cannot run validation worker on this platform".to_string()) Err("Cannot run validation worker on this platform".to_string())
} }
/// WASM code execution mode. /// The execution mode for the `ValidationPool`.
/// #[derive(Clone)]
/// > Note: When compiling for WASM, the `Remote` variants are not available. #[cfg_attr(not(any(target_os = "android", target_os = "unknown")), derive(Debug))]
pub enum ExecutionMode<'a> { pub enum ExecutionMode {
/// Execute in-process. The execution can not be interrupted or aborted. /// The validation worker is ran in a thread inside the same process.
Local, InProcess,
/// Remote execution in a spawned process. /// The validation worker is ran using the process' executable and the subcommand `validation-worker` is passed
Remote(&'a ValidationPool), /// following by the address of the shared memory.
ExternalProcessSelfHost(ValidationPool),
/// The validation worker is ran using the command provided and the argument provided. The address of the shared
/// memory is added at the end of the arguments.
ExternalProcessCustomHost {
/// Validation pool.
pool: ValidationPool,
/// Path to the validation worker. The file must exists and be executable.
binary: PathBuf,
/// List of arguments passed to the validation worker. The address of the shared memory will be automatically
/// added after the arguments.
args: Vec<String>,
},
} }
#[derive(Debug, derive_more::Display, derive_more::From)] #[derive(Debug, derive_more::Display, derive_more::From)]
/// Candidate validation error. /// Candidate validation error.
pub enum ValidationError { pub enum ValidationError {
@@ -132,19 +145,24 @@ impl std::error::Error for ValidationError {
pub fn validate_candidate( pub fn validate_candidate(
validation_code: &[u8], validation_code: &[u8],
params: ValidationParams, params: ValidationParams,
options: ExecutionMode<'_>, execution_mode: &ExecutionMode,
spawner: impl SpawnNamed + 'static, spawner: impl SpawnNamed + 'static,
) -> Result<ValidationResult, ValidationError> { ) -> Result<ValidationResult, ValidationError> {
match options { match execution_mode {
ExecutionMode::Local => { ExecutionMode::InProcess => {
validate_candidate_internal(validation_code, &params.encode(), spawner) validate_candidate_internal(validation_code, &params.encode(), spawner)
}, },
#[cfg(not(any(target_os = "android", target_os = "unknown")))] #[cfg(not(any(target_os = "android", target_os = "unknown")))]
ExecutionMode::Remote(pool) => { ExecutionMode::ExternalProcessSelfHost(pool) => {
pool.validate_candidate(validation_code, params) pool.validate_candidate(validation_code, params)
}, },
#[cfg(not(any(target_os = "android", target_os = "unknown")))]
ExecutionMode::ExternalProcessCustomHost { pool, binary, args } => {
let args: Vec<&str> = args.iter().map(|x| x.as_str()).collect();
pool.validate_candidate_custom(validation_code, params, binary, &args)
},
#[cfg(any(target_os = "android", target_os = "unknown"))] #[cfg(any(target_os = "android", target_os = "unknown"))]
ExecutionMode::Remote(_pool) => ExecutionMode::ExternalProcessSelfHost(_) | ExecutionMode::ExternalProcessCustomHost { .. } =>
Err(ValidationError::Internal(InternalError::System( Err(ValidationError::Internal(InternalError::System(
Box::<dyn std::error::Error + Send + Sync>::from( Box::<dyn std::error::Error + Send + Sync>::from(
"Remote validator not available".to_string() "Remote validator not available".to_string()
@@ -29,9 +29,9 @@ use log::{debug, trace};
use futures::executor::ThreadPool; use futures::executor::ThreadPool;
use sp_core::traits::SpawnNamed; use sp_core::traits::SpawnNamed;
/// CLI Argument to start in validation worker mode.
const WORKER_ARG: &'static str = "validation-worker"; const WORKER_ARG: &'static str = "validation-worker";
const WORKER_ARGS: &[&'static str] = &[WORKER_ARG]; /// CLI Argument to start in validation worker mode.
pub const WORKER_ARGS: &[&'static str] = &[WORKER_ARG];
/// Execution timeout in seconds; /// Execution timeout in seconds;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@@ -65,60 +65,60 @@ impl SpawnNamed for TaskExecutor {
} }
} }
/// The execution mode for the `ValidationPool`.
#[derive(Debug, Clone)]
pub enum ValidationExecutionMode {
/// The validation worker is ran in a thread inside the same process.
InProcess,
/// The validation worker is ran using the process' executable and the subcommand `validation-worker` is passed
/// following by the address of the shared memory.
ExternalProcessSelfHost,
/// The validation worker is ran using the command provided and the argument provided. The address of the shared
/// memory is added at the end of the arguments.
ExternalProcessCustomHost {
/// Path to the validation worker. The file must exists and be executable.
binary: PathBuf,
/// List of arguments passed to the validation worker. The address of the shared memory will be automatically
/// added after the arguments.
args: Vec<String>,
},
}
/// A pool of hosts. /// A pool of hosts.
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct ValidationPool { pub struct ValidationPool {
hosts: Arc<Vec<Mutex<ValidationHost>>>, hosts: Arc<Vec<Mutex<ValidationHost>>>,
execution_mode: ValidationExecutionMode,
} }
const DEFAULT_NUM_HOSTS: usize = 8; const DEFAULT_NUM_HOSTS: usize = 8;
impl ValidationPool { impl ValidationPool {
/// Creates a validation pool with the default configuration. /// Creates a validation pool with the default configuration.
pub fn new(execution_mode: ValidationExecutionMode) -> ValidationPool { pub fn new() -> ValidationPool {
ValidationPool { ValidationPool {
hosts: Arc::new((0..DEFAULT_NUM_HOSTS).map(|_| Default::default()).collect()), hosts: Arc::new((0..DEFAULT_NUM_HOSTS).map(|_| Default::default()).collect()),
execution_mode,
} }
} }
/// Validate a candidate under the given validation code using the next /// Validate a candidate under the given validation code using the next free validation host.
/// free validation host.
/// ///
/// This will fail if the validation code is not a proper parachain validation module. /// This will fail if the validation code is not a proper parachain validation module.
///
/// This function will use `std::env::current_exe()` with the default arguments [`WORKER_ARGS`] to run the worker.
pub fn validate_candidate( pub fn validate_candidate(
&self, &self,
validation_code: &[u8], validation_code: &[u8],
params: ValidationParams, params: ValidationParams,
) -> Result<ValidationResult, ValidationError> {
self.validate_candidate_custom(
validation_code,
params,
&env::current_exe().map_err(|err| ValidationError::Internal(err.into()))?,
WORKER_ARGS,
)
}
/// Validate a candidate under the given validation code using the next free validation host.
///
/// This will fail if the validation code is not a proper parachain validation module.
///
/// This function will use the command and the arguments provided in the function's arguments to run the worker.
pub fn validate_candidate_custom(
&self,
validation_code: &[u8],
params: ValidationParams,
command: &PathBuf,
args: &[&str],
) -> Result<ValidationResult, ValidationError> { ) -> Result<ValidationResult, ValidationError> {
for host in self.hosts.iter() { for host in self.hosts.iter() {
if let Some(mut host) = host.try_lock() { if let Some(mut host) = host.try_lock() {
return host.validate_candidate(validation_code, params, self.execution_mode.clone()); return host.validate_candidate(validation_code, params, command, args)
} }
} }
// all workers are busy, just wait for the first one // all workers are busy, just wait for the first one
self.hosts[0].lock().validate_candidate(validation_code, params, self.execution_mode.clone()) self.hosts[0].lock().validate_candidate(validation_code, params, command, args)
} }
} }
@@ -224,11 +224,32 @@ enum ValidationResultHeader {
unsafe impl Send for ValidationHost {} unsafe impl Send for ValidationHost {}
#[derive(Default)] struct ValidationHostMemory(SharedMem);
impl std::fmt::Debug for ValidationHostMemory {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "ValidationHostMemory")
}
}
impl std::ops::Deref for ValidationHostMemory {
type Target = SharedMem;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for ValidationHostMemory {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Default, Debug)]
struct ValidationHost { struct ValidationHost {
worker: Option<process::Child>, worker: Option<process::Child>,
worker_thread: Option<std::thread::JoinHandle<Result<(), String>>>, memory: Option<ValidationHostMemory>,
memory: Option<SharedMem>,
id: u32, id: u32,
} }
@@ -253,7 +274,7 @@ impl ValidationHost {
Ok(mem_config.create()?) Ok(mem_config.create()?)
} }
fn start_worker(&mut self, execution_mode: ValidationExecutionMode) -> Result<(), InternalError> { fn start_worker(&mut self, cmd: &PathBuf, args: &[&str]) -> Result<(), InternalError> {
if let Some(ref mut worker) = self.worker { if let Some(ref mut worker) = self.worker {
// Check if still alive // Check if still alive
if let Ok(None) = worker.try_wait() { if let Ok(None) = worker.try_wait() {
@@ -261,44 +282,23 @@ impl ValidationHost {
return Ok(()); return Ok(());
} }
} }
if self.worker_thread.is_some() {
return Ok(());
}
let memory = Self::create_memory()?; let memory = Self::create_memory()?;
let mut run_worker_process = |cmd: PathBuf, args: Vec<String>| -> Result<(), std::io::Error> { debug!("Starting worker at {:?} with arguments: {:?} and {:?}", cmd, args, memory.get_os_path());
debug!("Starting worker at {:?} with arguments: {:?} and {:?}", cmd, args, memory.get_os_path()); let worker = process::Command::new(cmd)
let worker = process::Command::new(cmd) .args(args)
.args(args) .arg(memory.get_os_path())
.arg(memory.get_os_path()) .stdin(process::Stdio::piped())
.stdin(process::Stdio::piped()) .spawn()?;
.spawn()?; self.id = worker.id();
self.id = worker.id(); self.worker = Some(worker);
self.worker = Some(worker);
Ok(())
};
match execution_mode {
ValidationExecutionMode::InProcess => {
let mem_id = memory.get_os_path().to_string();
self.worker_thread = Some(std::thread::spawn(move || run_worker(mem_id.as_str())));
},
ValidationExecutionMode::ExternalProcessSelfHost => run_worker_process(
env::current_exe()?,
WORKER_ARGS.iter().map(|x| x.to_string()).collect(),
)?,
ValidationExecutionMode::ExternalProcessCustomHost { binary, args } => run_worker_process(
binary,
args,
)?,
};
memory.wait( memory.wait(
Event::WorkerReady as usize, Event::WorkerReady as usize,
shared_memory::Timeout::Sec(EXECUTION_TIMEOUT_SEC as usize), shared_memory::Timeout::Sec(EXECUTION_TIMEOUT_SEC as usize),
)?; )?;
self.memory = Some(memory); self.memory = Some(ValidationHostMemory(memory));
Ok(()) Ok(())
} }
@@ -309,13 +309,14 @@ impl ValidationHost {
&mut self, &mut self,
validation_code: &[u8], validation_code: &[u8],
params: ValidationParams, params: ValidationParams,
execution_mode: ValidationExecutionMode, binary: &PathBuf,
args: &[&str],
) -> Result<ValidationResult, ValidationError> { ) -> Result<ValidationResult, ValidationError> {
if validation_code.len() > MAX_CODE_MEM { if validation_code.len() > MAX_CODE_MEM {
return Err(ValidationError::InvalidCandidate(InvalidCandidate::CodeTooLarge(validation_code.len()))); return Err(ValidationError::InvalidCandidate(InvalidCandidate::CodeTooLarge(validation_code.len())));
} }
// First, check if need to spawn the child process // First, check if need to spawn the child process
self.start_worker(execution_mode)?; self.start_worker(binary, args)?;
let memory = self.memory.as_mut() let memory = self.memory.as_mut()
.expect("memory is always `Some` after `start_worker` completes successfully"); .expect("memory is always `Some` after `start_worker` completes successfully");
{ {
@@ -25,7 +25,7 @@ use parachain::{
HeadData as GenericHeadData, HeadData as GenericHeadData,
ValidationParams, ValidationParams,
}, },
wasm_executor::{ValidationPool, ValidationExecutionMode} wasm_executor::{ValidationPool, ExecutionMode}
}; };
use codec::{Decode, Encode}; use codec::{Decode, Encode};
@@ -57,28 +57,27 @@ fn hash_head(head: &HeadData) -> [u8; 32] {
tiny_keccak::keccak256(head.encode().as_slice()) tiny_keccak::keccak256(head.encode().as_slice())
} }
fn validation_pool() -> ValidationPool { fn execution_mode() -> ExecutionMode {
let execution_mode = ValidationExecutionMode::ExternalProcessCustomHost { ExecutionMode::ExternalProcessCustomHost {
pool: ValidationPool::new(),
binary: std::env::current_exe().unwrap(), binary: std::env::current_exe().unwrap(),
args: WORKER_ARGS_TEST.iter().map(|x| x.to_string()).collect(), args: WORKER_ARGS_TEST.iter().map(|x| x.to_string()).collect(),
}; }
ValidationPool::new(execution_mode)
} }
#[test] #[test]
fn execute_good_on_parent_with_inprocess_validation() { fn execute_good_on_parent_with_inprocess_validation() {
let pool = ValidationPool::new(ValidationExecutionMode::InProcess); let execution_mode = ExecutionMode::InProcess;
execute_good_on_parent(pool); execute_good_on_parent(execution_mode);
} }
#[test] #[test]
pub fn execute_good_on_parent_with_external_process_validation() { pub fn execute_good_on_parent_with_external_process_validation() {
let pool = validation_pool(); let execution_mode = execution_mode();
execute_good_on_parent(pool); execute_good_on_parent(execution_mode);
} }
fn execute_good_on_parent(pool: ValidationPool) { fn execute_good_on_parent(execution_mode: ExecutionMode) {
let parent_head = HeadData { let parent_head = HeadData {
number: 0, number: 0,
parent_hash: [0; 32], parent_hash: [0; 32],
@@ -99,7 +98,7 @@ fn execute_good_on_parent(pool: ValidationPool) {
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
}, },
parachain::wasm_executor::ExecutionMode::Remote(&pool), &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
).unwrap(); ).unwrap();
@@ -115,7 +114,7 @@ fn execute_good_chain_on_parent() {
let mut number = 0; let mut number = 0;
let mut parent_hash = [0; 32]; let mut parent_hash = [0; 32];
let mut last_state = 0; let mut last_state = 0;
let pool = validation_pool(); let execution_mode = execution_mode();
for add in 0..10 { for add in 0..10 {
let parent_head = HeadData { let parent_head = HeadData {
@@ -137,7 +136,7 @@ fn execute_good_chain_on_parent() {
relay_chain_height: number as RelayChainBlockNumber + 1, relay_chain_height: number as RelayChainBlockNumber + 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
}, },
parachain::wasm_executor::ExecutionMode::Remote(&pool), &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
).unwrap(); ).unwrap();
@@ -155,7 +154,7 @@ fn execute_good_chain_on_parent() {
#[test] #[test]
fn execute_bad_on_parent() { fn execute_bad_on_parent() {
let pool = validation_pool(); let execution_mode = execution_mode();
let parent_head = HeadData { let parent_head = HeadData {
number: 0, number: 0,
@@ -176,7 +175,7 @@ fn execute_bad_on_parent() {
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
}, },
parachain::wasm_executor::ExecutionMode::Remote(&pool), &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
).unwrap_err(); ).unwrap_err();
} }
@@ -21,21 +21,20 @@ const WORKER_ARGS_TEST: &[&'static str] = &["--nocapture", "validation_worker"];
use crate::adder; use crate::adder;
use parachain::{ use parachain::{
primitives::{BlockData, ValidationParams}, primitives::{BlockData, ValidationParams},
wasm_executor::{ValidationError, InvalidCandidate, EXECUTION_TIMEOUT_SEC, ValidationExecutionMode, ValidationPool}, wasm_executor::{ValidationError, InvalidCandidate, EXECUTION_TIMEOUT_SEC, ExecutionMode, ValidationPool},
}; };
fn validation_pool() -> ValidationPool { fn execution_mode() -> ExecutionMode {
let execution_mode = ValidationExecutionMode::ExternalProcessCustomHost { ExecutionMode::ExternalProcessCustomHost {
pool: ValidationPool::new(),
binary: std::env::current_exe().unwrap(), binary: std::env::current_exe().unwrap(),
args: WORKER_ARGS_TEST.iter().map(|x| x.to_string()).collect(), args: WORKER_ARGS_TEST.iter().map(|x| x.to_string()).collect(),
}; }
ValidationPool::new(execution_mode)
} }
#[test] #[test]
fn terminates_on_timeout() { fn terminates_on_timeout() {
let pool = validation_pool(); let execution_mode = execution_mode();
let result = parachain::wasm_executor::validate_candidate( let result = parachain::wasm_executor::validate_candidate(
halt::wasm_binary_unwrap(), halt::wasm_binary_unwrap(),
@@ -45,7 +44,7 @@ fn terminates_on_timeout() {
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
}, },
parachain::wasm_executor::ExecutionMode::Remote(&pool), &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
); );
match result { match result {
@@ -59,11 +58,11 @@ fn terminates_on_timeout() {
#[test] #[test]
fn parallel_execution() { fn parallel_execution() {
let pool = validation_pool(); let execution_mode = execution_mode();
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let pool2 = pool.clone(); let execution_mode2 = execution_mode.clone();
let thread = std::thread::spawn(move || let thread = std::thread::spawn(move ||
parachain::wasm_executor::validate_candidate( parachain::wasm_executor::validate_candidate(
halt::wasm_binary_unwrap(), halt::wasm_binary_unwrap(),
@@ -73,7 +72,7 @@ fn parallel_execution() {
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
}, },
parachain::wasm_executor::ExecutionMode::Remote(&pool2), &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
).ok()); ).ok());
let _ = parachain::wasm_executor::validate_candidate( let _ = parachain::wasm_executor::validate_candidate(
@@ -84,7 +83,7 @@ fn parallel_execution() {
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
}, },
parachain::wasm_executor::ExecutionMode::Remote(&pool), &execution_mode2,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
); );
thread.join().unwrap(); thread.join().unwrap();