polkadot_node_core_pvf_common/error.rs
1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
16
17use crate::prepare::{PrepareSuccess, PrepareWorkerSuccess};
18use codec::{Decode, Encode};
19pub use sc_executor_common::error::Error as ExecuteError;
20
21/// Result of PVF preparation from a worker, with checksum of the compiled PVF and stats of the
22/// preparation if successful.
23pub type PrepareWorkerResult = Result<PrepareWorkerSuccess, PrepareError>;
24
25/// Result of PVF preparation propagated all the way back to the host, with path to the concluded
26/// artifact and stats of the preparation if successful.
27pub type PrepareResult = Result<PrepareSuccess, PrepareError>;
28
29/// Result of prechecking PVF performed by the validation host. Contains stats about the preparation
30/// if successful.
31pub type PrecheckResult = Result<(), PrepareError>;
32
33/// An error that occurred during the prepare part of the PVF pipeline.
34// Codec indexes are intended to stabilize pre-encoded payloads (see `OOM_PAYLOAD`)
35#[derive(thiserror::Error, Debug, Clone, Encode, Decode)]
36pub enum PrepareError {
37 /// During the prevalidation stage of preparation an issue was found with the PVF.
38 #[codec(index = 0)]
39 #[error("prepare: prevalidation error: {0}")]
40 Prevalidation(String),
41 /// Compilation failed for the given PVF.
42 #[codec(index = 1)]
43 #[error("prepare: preparation error: {0}")]
44 Preparation(String),
45 /// Instantiation of the WASM module instance failed.
46 #[codec(index = 2)]
47 #[error("prepare: runtime construction: {0}")]
48 RuntimeConstruction(String),
49 /// An unexpected error has occurred in the preparation job.
50 #[codec(index = 3)]
51 #[error("prepare: job error: {0}")]
52 JobError(String),
53 /// Failed to prepare the PVF due to the time limit.
54 #[codec(index = 4)]
55 #[error("prepare: timeout")]
56 TimedOut,
57 /// An IO error occurred. This state is reported by either the validation host or by the
58 /// worker.
59 #[codec(index = 5)]
60 #[error("prepare: io error while receiving response: {0}")]
61 IoErr(String),
62 /// The temporary file for the artifact could not be created at the given cache path. This
63 /// state is reported by the validation host (not by the worker).
64 #[codec(index = 6)]
65 #[error("prepare: error creating tmp file: {0}")]
66 CreateTmpFile(String),
67 /// The response from the worker is received, but the file cannot be renamed (moved) to the
68 /// final destination location. This state is reported by the validation host (not by the
69 /// worker).
70 #[codec(index = 7)]
71 #[error("prepare: error renaming tmp file ({src:?} -> {dest:?}): {err}")]
72 RenameTmpFile {
73 err: String,
74 // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible
75 // conversion to `Option<String>`.
76 src: Option<String>,
77 dest: Option<String>,
78 },
79 /// Memory limit reached
80 #[codec(index = 8)]
81 #[error("prepare: out of memory")]
82 OutOfMemory,
83 /// The response from the worker is received, but the worker cache could not be cleared. The
84 /// worker has to be killed to avoid jobs having access to data from other jobs. This state is
85 /// reported by the validation host (not by the worker).
86 #[codec(index = 9)]
87 #[error("prepare: error clearing worker cache: {0}")]
88 ClearWorkerDir(String),
89 /// The preparation job process died, due to OOM, a seccomp violation, or some other factor.
90 #[codec(index = 10)]
91 #[error("prepare: prepare job with pid {job_pid} died: {err}")]
92 JobDied { err: String, job_pid: i32 },
93 /// Some error occurred when interfacing with the kernel.
94 #[codec(index = 11)]
95 #[error("prepare: error interfacing with the kernel: {0}")]
96 Kernel(String),
97 /// Code blob failed to decompress
98 #[codec(index = 12)]
99 #[error("prepare: could not decompress code blob: {0}")]
100 CouldNotDecompressCodeBlob(String),
101}
102
103impl PrepareError {
104 /// Returns whether this is a deterministic error, i.e. one that should trigger reliably. Those
105 /// errors depend on the PVF itself and the sc-executor/wasmtime logic.
106 ///
107 /// Non-deterministic errors can happen spuriously. Typically, they occur due to resource
108 /// starvation, e.g. under heavy load or memory pressure. Those errors are typically transient
109 /// but may persist e.g. if the node is run by overwhelmingly underpowered machine.
110 pub fn is_deterministic(&self) -> bool {
111 use PrepareError::*;
112 match self {
113 Prevalidation(_) |
114 Preparation(_) |
115 JobError(_) |
116 OutOfMemory |
117 CouldNotDecompressCodeBlob(_) => true,
118 IoErr(_) |
119 JobDied { .. } |
120 CreateTmpFile(_) |
121 RenameTmpFile { .. } |
122 ClearWorkerDir(_) |
123 Kernel(_) => false,
124 // Can occur due to issues with the PVF, but also due to factors like local load.
125 TimedOut => false,
126 // Can occur due to issues with the PVF, but also due to local errors.
127 RuntimeConstruction(_) => false,
128 }
129 }
130}
131
132/// Some internal error occurred.
133///
134/// Should only ever be used for validation errors independent of the candidate and PVF, or for
135/// errors we ruled out during pre-checking (so preparation errors are fine).
136#[derive(thiserror::Error, Debug, Clone, Encode, Decode)]
137pub enum InternalValidationError {
138 /// Some communication error occurred with the host.
139 #[error("validation: some communication error occurred with the host: {0}")]
140 HostCommunication(String),
141 /// Host could not create a hard link to the artifact path.
142 #[error("validation: host could not create a hard link to the artifact path: {0}")]
143 CouldNotCreateLink(String),
144 /// Could not find or open compiled artifact file.
145 #[error("validation: could not find or open compiled artifact file: {0}")]
146 CouldNotOpenFile(String),
147 /// Could not create a pipe between the worker and a child process.
148 #[error("validation: could not create pipe: {0}")]
149 CouldNotCreatePipe(String),
150 /// Host could not clear the worker cache after a job.
151 #[error("validation: host could not clear the worker cache ({path:?}) after a job: {err}")]
152 CouldNotClearWorkerDir {
153 err: String,
154 // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible
155 // conversion to `Option<String>`.
156 path: Option<String>,
157 },
158 /// Some error occurred when interfacing with the kernel.
159 #[error("validation: error interfacing with the kernel: {0}")]
160 Kernel(String),
161 /// Some non-deterministic preparation error occurred.
162 #[error("validation: prepare: {0}")]
163 NonDeterministicPrepareError(PrepareError),
164}