Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

PVF host prechecking support v2 #4123

Merged
merged 24 commits into from
Nov 13, 2021
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
46 changes: 23 additions & 23 deletions node/core/pvf/src/artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

use crate::{error::PrepareError, host::PrepareResultSender};
use always_assert::always;
use async_std::path::{Path, PathBuf};
use parity_scale_codec::{Decode, Encode};
Expand All @@ -23,30 +24,19 @@ use std::{
time::{Duration, SystemTime},
};

/// A final product of preparation process. Contains either a ready to run compiled artifact or
/// a description what went wrong.
/// A wrapper for the compiled PVF code.
#[derive(Encode, Decode)]
pub enum Artifact {
/// During the prevalidation stage of preparation an issue was found with the PVF.
PrevalidationErr(String),
/// Compilation failed for the given PVF.
PreparationErr(String),
/// This state indicates that the process assigned to prepare the artifact wasn't responsible
/// or were killed. This state is reported by the validation host (not by the worker).
DidntMakeIt,
/// The PVF passed all the checks and is ready for execution.
Compiled { compiled_artifact: Vec<u8> },
}
pub struct CompiledArtifact(Vec<u8>);

impl Artifact {
/// Serializes this struct into a byte buffer.
pub fn serialize(&self) -> Vec<u8> {
self.encode()
impl CompiledArtifact {
pub fn new(code: Vec<u8>) -> Self {
Self(code)
}
}

/// Deserialize the given byte buffer to an artifact.
pub fn deserialize(mut bytes: &[u8]) -> Result<Self, String> {
Artifact::decode(&mut bytes).map_err(|e| format!("{:?}", e))
impl AsRef<[u8]> for CompiledArtifact {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}

Expand Down Expand Up @@ -116,7 +106,10 @@ pub enum ArtifactState {
last_time_needed: SystemTime,
},
/// A task to prepare this artifact is scheduled.
Preparing,
Preparing { waiting_for_response: Vec<PrepareResultSender> },
/// The code couldn't be compiled due to an error. Such artifacts
/// never reach the executor and stay in the host's memory.
FailedToProcess(PrepareError),
}

/// A container of all known artifact ids and their states.
Expand Down Expand Up @@ -152,9 +145,16 @@ impl Artifacts {
///
/// This function must be used only for brand-new artifacts and should never be used for
/// replacing existing ones.
pub fn insert_preparing(&mut self, artifact_id: ArtifactId) {
pub fn insert_preparing(
&mut self,
artifact_id: ArtifactId,
waiting_for_response: Vec<PrepareResultSender>,
) {
// See the precondition.
always!(self.artifacts.insert(artifact_id, ArtifactState::Preparing).is_none());
always!(self
.artifacts
.insert(artifact_id, ArtifactState::Preparing { waiting_for_response })
.is_none());
}

/// Insert an artifact with the given ID as "prepared".
Expand Down
28 changes: 28 additions & 0 deletions node/core/pvf/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

use parity_scale_codec::{Decode, Encode};

/// An error that occurred during the prepare part of the PVF pipeline.
#[derive(Debug, Clone, Encode, Decode)]
pub enum PrepareError {
/// During the prevalidation stage of preparation an issue was found with the PVF.
Prevalidation(String),
/// Compilation failed for the given PVF.
Preparation(String),
/// Failed to prepare the PVF due to the time limit.
TimedOut,
/// This state indicates that the process assigned to prepare the artifact wasn't responsible
/// or were killed. This state is reported by the validation host (not by the worker).
DidNotMakeIt,
}

/// A error raised during validation of the candidate.
#[derive(Debug, Clone)]
pub enum ValidationError {
Expand Down Expand Up @@ -54,3 +70,15 @@ pub enum InvalidCandidate {
/// PVF execution (compilation is not included) took more time than was allotted.
HardTimeout,
}

impl From<PrepareError> for ValidationError {
fn from(error: PrepareError) -> Self {
let error_str = match error {
PrepareError::Prevalidation(err) => err,
PrepareError::Preparation(err) => err,
PrepareError::TimedOut => "preparation timeout".to_owned(),
PrepareError::DidNotMakeIt => "communication error".to_owned(),
};
ValidationError::InvalidCandidate(InvalidCandidate::WorkerReportedError(error_str))
}
}
16 changes: 5 additions & 11 deletions node/core/pvf/src/execute/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

use crate::{
artifacts::{Artifact, ArtifactPathId},
artifacts::{ArtifactPathId, CompiledArtifact},
executor_intf::TaskExecutor,
worker_common::{
bytes_to_path, framed_recv, framed_send, path_to_bytes, spawn_with_program_path,
Expand Down Expand Up @@ -49,8 +49,8 @@ pub enum Outcome {
/// PVF execution completed successfully and the result is returned. The worker is ready for
/// another job.
Ok { result_descriptor: ValidationResult, duration_ms: u64, idle_worker: IdleWorker },
/// The candidate validation failed. It may be for example because the preparation process
/// produced an error or the wasm execution triggered a trap.
/// The candidate validation failed. It may be for example because the wasm execution triggered a trap.
/// Errors related to the preparation process are not expected to be encountered by the execution workers.
InvalidCandidate { err: String, idle_worker: IdleWorker },
/// An internal error happened during the validation. Such an error is most likely related to
/// some transient glitch.
Expand Down Expand Up @@ -216,18 +216,12 @@ async fn validate_using_artifact(
Ok(b) => b,
};

let artifact = match Artifact::deserialize(&artifact_bytes) {
let artifact = match CompiledArtifact::decode(&mut artifact_bytes.as_slice()) {
Err(e) => return Response::InternalError(format!("artifact deserialization: {:?}", e)),
Ok(a) => a,
};

let compiled_artifact = match &artifact {
Artifact::PrevalidationErr(msg) => return Response::format_invalid("prevalidation", msg),
Artifact::PreparationErr(msg) => return Response::format_invalid("preparation", msg),
Artifact::DidntMakeIt => return Response::format_invalid("preparation timeout", ""),

Artifact::Compiled { compiled_artifact } => compiled_artifact,
};
let compiled_artifact = artifact.as_ref();

let validation_started_at = Instant::now();
let descriptor_bytes = match unsafe {
Expand Down
2 changes: 1 addition & 1 deletion node/core/pvf/src/executor_intf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const CONFIG: Config = Config {
native_stack_max: 256 * 1024 * 1024,
}),
canonicalize_nans: true,
parallel_compilation: true,
parallel_compilation: false,
slumber marked this conversation as resolved.
Show resolved Hide resolved
},
};

Expand Down
Loading