-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Candidate Validation/PVF: more fidelity of error metrics #6479
Changes from 6 commits
079364c
b70c53a
b0e1bc1
9578ee9
fe79750
1593e16
77360f8
8ff6d1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,12 +24,50 @@ pub type PrepareResult = Result<Duration, PrepareError>; | |
/// An error that occurred during the prepare part of the PVF pipeline. | ||
#[derive(Debug, Clone, Encode, Decode)] | ||
pub enum PrepareError { | ||
/// An error that should trigger reliably. See [`DeterministicError`]. | ||
Deterministic(DeterministicError), | ||
/// An error that may happen spuriously. See [`NonDeterministicError`]. | ||
NonDeterministic(NonDeterministicError), | ||
} | ||
|
||
impl fmt::Display for PrepareError { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
use PrepareError::*; | ||
match self { | ||
Deterministic(err) => write!(f, "{}", err), | ||
NonDeterministic(err) => write!(f, "{}", err), | ||
} | ||
} | ||
} | ||
|
||
/// A deterministic error, i.e. one that should trigger reliably. Those errors depend on the PVF | ||
/// itself and the sc-executor/wasmtime logic. | ||
#[derive(Debug, Clone, Encode, Decode)] | ||
pub enum DeterministicError { | ||
/// During the prevalidation stage of preparation an issue was found with the PVF. | ||
Prevalidation(String), | ||
/// Compilation failed for the given PVF. | ||
Preparation(String), | ||
/// An unexpected panic has occured in the preparation worker. | ||
Panic(String), | ||
} | ||
|
||
impl fmt::Display for DeterministicError { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
use DeterministicError::*; | ||
match self { | ||
Prevalidation(err) => write!(f, "prevalidation: {}", err), | ||
Preparation(err) => write!(f, "preparation: {}", err), | ||
Panic(err) => write!(f, "panic: {}", err), | ||
} | ||
} | ||
} | ||
|
||
/// Non-deterministic errors can happen spuriously. Typically, they occur due to resource | ||
/// starvation, e.g. under heavy load or memory pressure. Those errors are typically transient but | ||
/// may persist e.g. if the node is run by overwhelmingly underpowered machine. | ||
#[derive(Debug, Clone, Encode, Decode)] | ||
pub enum NonDeterministicError { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get the naming of deterministic and non deterministic. However, I think this could be improved. I don't have a better terminology at hand right now, but I think it could be better. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it's awkward. Maybe |
||
/// Failed to prepare the PVF due to the time limit. | ||
TimedOut, | ||
/// An IO error occurred while receiving the result from the worker process. This state is reported by the | ||
|
@@ -43,29 +81,10 @@ pub enum PrepareError { | |
RenameTmpFileErr(String), | ||
} | ||
|
||
impl PrepareError { | ||
/// Returns whether this is a deterministic error, i.e. one that should trigger reliably. Those | ||
/// errors depend on the PVF itself and the sc-executor/wasmtime logic. | ||
/// | ||
/// Non-deterministic errors can happen spuriously. Typically, they occur due to resource | ||
/// starvation, e.g. under heavy load or memory pressure. Those errors are typically transient | ||
/// but may persist e.g. if the node is run by overwhelmingly underpowered machine. | ||
pub fn is_deterministic(&self) -> bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you remove this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I figured that now we can just match on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah for sure, but calling this method is less code 🤣 But yeah, no strong argument here. |
||
use PrepareError::*; | ||
match self { | ||
Prevalidation(_) | Preparation(_) | Panic(_) => true, | ||
TimedOut | IoErr | CreateTmpFileErr(_) | RenameTmpFileErr(_) => false, | ||
} | ||
} | ||
} | ||
|
||
impl fmt::Display for PrepareError { | ||
impl fmt::Display for NonDeterministicError { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
use PrepareError::*; | ||
use NonDeterministicError::*; | ||
match self { | ||
Prevalidation(err) => write!(f, "prevalidation: {}", err), | ||
Preparation(err) => write!(f, "preparation: {}", err), | ||
Panic(err) => write!(f, "panic: {}", err), | ||
TimedOut => write!(f, "prepare: timeout"), | ||
IoErr => write!(f, "prepare: io error while receiving response"), | ||
CreateTmpFileErr(err) => write!(f, "prepare: error creating tmp file: {}", err), | ||
|
@@ -79,16 +98,20 @@ impl fmt::Display for PrepareError { | |
pub enum ValidationError { | ||
/// The error was raised because the candidate is invalid. | ||
InvalidCandidate(InvalidCandidate), | ||
/// This error is raised due to inability to serve the request. | ||
InternalError(String), | ||
/// This error is raised due to inability to serve the request during preparation. | ||
InternalPrepare(NonDeterministicError), | ||
/// This error is raised due to inability to serve the request during execution. | ||
InternalExecute(String), | ||
/// This error is raised due to inability to serve the request for some other reason. | ||
InternalOther(String), | ||
} | ||
|
||
/// A description of an error raised during executing a PVF and can be attributed to the combination | ||
/// of the candidate [`polkadot_parachain::primitives::ValidationParams`] and the PVF. | ||
#[derive(Debug, Clone)] | ||
pub enum InvalidCandidate { | ||
/// PVF preparation ended up with a deterministic error. | ||
PrepareError(String), | ||
PrepareError(DeterministicError), | ||
/// The failure is reported by the execution worker. The string contains the error message. | ||
WorkerReportedError(String), | ||
/// The worker has died during validation of a candidate. That may fall in one of the following | ||
|
@@ -123,12 +146,12 @@ impl From<PrepareError> for ValidationError { | |
// We treat the deterministic errors as `InvalidCandidate`. Should those occur they could | ||
// potentially trigger disputes. | ||
// | ||
// All non-deterministic errors are qualified as `InternalError`s and will not trigger | ||
// All non-deterministic errors are qualified as `InternalPrepareError`s and will not trigger | ||
// disputes. | ||
if error.is_deterministic() { | ||
ValidationError::InvalidCandidate(InvalidCandidate::PrepareError(error.to_string())) | ||
} else { | ||
ValidationError::InternalError(error.to_string()) | ||
match error { | ||
PrepareError::Deterministic(error) => | ||
ValidationError::InvalidCandidate(InvalidCandidate::PrepareError(error)), | ||
PrepareError::NonDeterministic(error) => ValidationError::InternalPrepareError(error), | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO prepare error being deterministic or not is a property that's not necessarily needed everywhere this enum is used.
looked much better to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These variants do end up being useful actually, there's several places where only "deterministic" (or not) errors are allowed, and having
PrepareError
in such places didn't quite seem correct.If we pursue this further, I would probably rename to
PrepareFailedError
andPrepareInvalidError
or something (not totally sure, haven't looked at this in a while).