referrerpolicy=no-referrer-when-downgrade

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}