Executor Environment parameterization (#6161)

* Re-apply changes without Diener, rebase to the lastest master

* Cache pruning

* Bit-pack InstantiationStrategy

* Move ExecutorParams version inside the structure itself

* Rework runtime API and executor parameters storage

* Pass executor parameters through backing subsystem

* Update Cargo.lock

* Introduce `ExecutorParams` to approval voting subsys

* Introduce `ExecutorParams` to dispute coordinator

* `cargo fmt`

* Simplify requests from backing subsys

* Fix tests

* Replace manual config cloning with `.clone()`

* Move constants to module

* Parametrize executor performing PVF pre-check

* Fix Malus

* Fix test runtime

* Introduce session executor params as a constant defined by session info
pallet

* Use Parity SCALE codec instead of hand-crafted binary encoding

* Get rid of constants; Add docs

* Get rid of constants

* Minor typo

* Fix Malus after rebase

* `cargo fmt`

* Use transparent SCALE encoding instead of explicit

* Clean up

* Get rid of relay parent to session index mapping

* Join environment type and version in a single enum element

* Use default execution parameters if running an old runtime

* `unwrap()` -> `expect()`

* Correct API version

* Constants are back in town

* Use constants for execution environment types

* Artifact separation, first try

* Get rid of explicit version

* PVF execution queue worker separation

* Worker handshake

* Global renaming

* Minor fixes resolving discussions

* Two-stage requesting of executor params to make use of runtime API cache

* Proper error handling in pvf-checker

* Executor params storage bootstrapping

* Propagate migration to v3 network runtimes

* Fix storage versioning

* Ensure `ExecutorParams` serialization determinism; Add comments

* Rename constants to make things a bit more deterministic
Get rid of stale code

* Tidy up a structure of active PVFs

* Minor formatting

* Fix comment

* Add try-runtime hooks

* Add storage version write on upgrade

Co-authored-by: Andronik <write@reusable.software>

* Add pre- and post-upgrade assertions

* Require to specify environment type; Remove redundant `impl`s

* Add `ExecutorParamHash` creation from `H256`

* Fix candidate validation subsys tests

* Return splittable error from executor params request fn

* Revert "Return splittable error from executor params request fn"

This reverts commit a0b274177d8bb2f6e13c066741892ecd2e72a456.

* Decompose approval voting metrics

* Use more relevant errors

* Minor formatting fix

* Assert a valid environment type instead of checking

* Fix `try-runtime` hooks

* After-merge fixes

* Add migration logs

* Remove dead code

* Fix tests

* Fix tests

* Back to the strongly typed implementation

* Promote strong types to executor interface

* Remove stale comment

* Move executor params to `SessionInfo`: primitives and runtime

* Move executor params to `SessionInfo`: node

* Try to bump primitives and API version

* Get rid of `MallocSizeOf`

* Bump target API version to v4

* Make use of session index already in place

* Back to v3

* Fix all the tests

* Add migrations to all the runtimes

* Make use of existing `SessionInfo` in approval voting subsys

* Rename `TARGET` -> `LOG_TARGET`

* Bump all the primitives to v3

* Fix Rococo ParachainHost API version

* Use `RollingSessionWindow` to acquire `ExecutorParams` in disputes

* Fix nits from discussions; add comments

* Re-evaluate queue logic

* Rework job assignment in execution queue

* Add documentation

* Use `RuntimeInfo` to obtain `SessionInfo` (with blackjack and caching)

* Couple `Pvf` with `ExecutorParams` wherever possible

* Put members of `PvfWithExecutorParams` under `Arc` for cheap cloning

* Fix comment

* Fix CI tests

* Fix clippy warnings

* Address nits from discussions

* Add a placeholder for raw data

* Fix non exhaustive match

* Remove redundant reexports and fix imports

* Keep only necessary semantic features, as discussed

* Rework `RuntimeInfo` to support mock implementation for tests

* Remove unneeded bound

* `cargo fmt`

* Revert "Remove unneeded bound"

This reverts commit 932463f26b00ce290e1e61848eb9328632ef8a61.

* Fix PVF host tests

* Fix PVF checker tests

* Fix overseer declarations

* Simplify tests

* `MAX_KEEP_WAITING` timeout based on `BACKGING_EXECUTION_TIMEOUT`

* Add a unit test for varying executor parameters

* Minor fixes from discussions

* Add prechecking max. memory parameter (see paritytech/srlabs_findings#110)

* Fix and improve a test

* Remove `ExecutionEnvironment` and `RawData`

* New primitives versioning in parachain host API

* `disputes()` implementation for Kusama and Polkadot

* Move `ExecutorParams` from `vstaging` to stable primitives

* Move disputes from `vstaging` to stable implementation

* Fix `try-runtime`

* Fixes after merge

* Move `ExecutorParams` to the bottom of `SessionInfo`

* Revert "Move executor params to `SessionInfo`: primitives and runtime"

This reverts commit dfcfb85fefd1c5be6c8a8f72dc09fd1809cfa9ce.

* Always use fresh activated live hash in pvf precheck
(re-apply 34b09a4c20de17e7926ed942cd0d657d18f743fa)

* Fixing tests (broken commit)

* Fix candidate validation tests

* Fix PVF host test

* Minor fixes

* Address discussions

* Restore migration

* Fix `use` to only include what is needed instead of `*`

* Add comment to never touch `DEFAULT_CONFIG`

* Update migration to set default `ExecutorParams` for `dispute_period`
sessions back

* Use `earliest_stored_session` instead of calculations

* Nit

* Add logs

* Treat any runtime error as `NotSupported` again

* Always return default executor params if not available

* Revert "Always return default executor params if not available"

This reverts commit b58ac4482ef444c67a9852d5776550d08e312f30.

* Add paritytech/substrate#9997 workaround

* `cargo fmt`

* Remove migration (again!)

* Bump executor params to API v4 (backport from #6698)

---------

Co-authored-by: Andronik <write@reusable.software>
This commit is contained in:
s0me0ne-unkn0wn
2023-02-15 12:26:09 +01:00
committed by GitHub
parent 7f6b8e6df9
commit dd0a556665
40 changed files with 1243 additions and 330 deletions
@@ -24,8 +24,8 @@
#![warn(missing_docs)]
use polkadot_node_core_pvf::{
InvalidCandidate as WasmInvalidCandidate, PrepareError, PrepareStats, Pvf, ValidationError,
ValidationHost,
InvalidCandidate as WasmInvalidCandidate, PrepareError, PrepareStats, Pvf,
PvfWithExecutorParams, ValidationError, ValidationHost,
};
use polkadot_node_primitives::{
BlockData, InvalidCandidate, PoV, ValidationResult, POV_BOMB_LIMIT, VALIDATION_CODE_BOMB_LIMIT,
@@ -39,10 +39,11 @@ use polkadot_node_subsystem::{
overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult,
SubsystemSender,
};
use polkadot_node_subsystem_util::executor_params_at_relay_parent;
use polkadot_parachain::primitives::{ValidationParams, ValidationResult as WasmValidationResult};
use polkadot_primitives::{
CandidateCommitments, CandidateDescriptor, CandidateReceipt, Hash, OccupiedCoreAssumption,
PersistedValidationData, ValidationCode, ValidationCodeHash,
vstaging::ExecutorParams, CandidateCommitments, CandidateDescriptor, CandidateReceipt, Hash,
OccupiedCoreAssumption, PersistedValidationData, ValidationCode, ValidationCodeHash,
};
use parity_scale_codec::Encode;
@@ -175,12 +176,14 @@ async fn run<Context>(
response_sender,
) => {
let bg = {
let mut sender = ctx.sender().clone();
let metrics = metrics.clone();
let validation_host = validation_host.clone();
async move {
let _timer = metrics.time_validate_from_exhaustive();
let res = validate_candidate_exhaustive(
&mut sender,
validation_host,
persisted_validation_data,
validation_code,
@@ -307,18 +310,38 @@ where
},
};
let validation_code = match sp_maybe_compressed_blob::decompress(
let executor_params =
if let Ok(executor_params) = executor_params_at_relay_parent(relay_parent, sender).await {
gum::debug!(
target: LOG_TARGET,
?relay_parent,
?validation_code_hash,
"precheck: acquired executor params for the session: {:?}",
executor_params,
);
executor_params
} else {
gum::warn!(
target: LOG_TARGET,
?relay_parent,
?validation_code_hash,
"precheck: failed to acquire executor params for the session, thus voting against.",
);
return PreCheckOutcome::Invalid
};
let pvf_with_params = match sp_maybe_compressed_blob::decompress(
&validation_code.0,
VALIDATION_CODE_BOMB_LIMIT,
) {
Ok(code) => Pvf::from_code(code.into_owned()),
Ok(code) => PvfWithExecutorParams::new(Pvf::from_code(code.into_owned()), executor_params),
Err(e) => {
gum::debug!(target: LOG_TARGET, err=?e, "precheck: cannot decompress validation code");
return PreCheckOutcome::Invalid
},
};
match validation_backend.precheck_pvf(validation_code).await {
match validation_backend.precheck_pvf(pvf_with_params).await {
Ok(_) => PreCheckOutcome::Valid,
Err(prepare_err) =>
if prepare_err.is_deterministic() {
@@ -456,6 +479,7 @@ where
};
let validation_result = validate_candidate_exhaustive(
sender,
validation_host,
validation_data,
validation_code,
@@ -490,7 +514,8 @@ where
validation_result
}
async fn validate_candidate_exhaustive(
async fn validate_candidate_exhaustive<Sender>(
sender: &mut Sender,
mut validation_backend: impl ValidationBackend + Send,
persisted_validation_data: PersistedValidationData,
validation_code: ValidationCode,
@@ -498,7 +523,10 @@ async fn validate_candidate_exhaustive(
pov: Arc<PoV>,
timeout: Duration,
metrics: &Metrics,
) -> Result<ValidationResult, ValidationFailed> {
) -> Result<ValidationResult, ValidationFailed>
where
Sender: SubsystemSender<RuntimeApiMessage>,
{
let _timer = metrics.time_validate_candidate_exhaustive();
let validation_code_hash = validation_code.hash();
@@ -554,8 +582,34 @@ async fn validate_candidate_exhaustive(
relay_parent_storage_root: persisted_validation_data.relay_parent_storage_root,
};
let executor_params = if let Ok(executor_params) =
executor_params_at_relay_parent(candidate_receipt.descriptor.relay_parent, sender).await
{
gum::debug!(
target: LOG_TARGET,
?validation_code_hash,
?para_id,
"Acquired executor params for the session: {:?}",
executor_params,
);
executor_params
} else {
gum::warn!(
target: LOG_TARGET,
?validation_code_hash,
?para_id,
"Failed to acquire executor params for the session",
);
return Ok(ValidationResult::Invalid(InvalidCandidate::BadParent))
};
let result = validation_backend
.validate_candidate_with_retry(raw_validation_code.to_vec(), timeout, params)
.validate_candidate_with_retry(
raw_validation_code.to_vec(),
timeout,
params,
executor_params,
)
.await;
if let Err(ref error) = result {
@@ -613,7 +667,7 @@ trait ValidationBackend {
/// Tries executing a PVF a single time (no retries).
async fn validate_candidate(
&mut self,
pvf: Pvf,
pvf_with_params: PvfWithExecutorParams,
timeout: Duration,
encoded_params: Vec<u8>,
) -> Result<WasmValidationResult, ValidationError>;
@@ -625,12 +679,14 @@ trait ValidationBackend {
raw_validation_code: Vec<u8>,
timeout: Duration,
params: ValidationParams,
executor_params: ExecutorParams,
) -> Result<WasmValidationResult, ValidationError> {
// Construct the PVF a single time, since it is an expensive operation. Cloning it is cheap.
let pvf = Pvf::from_code(raw_validation_code);
let pvf_with_params =
PvfWithExecutorParams::new(Pvf::from_code(raw_validation_code), executor_params);
let mut validation_result =
self.validate_candidate(pvf.clone(), timeout, params.encode()).await;
self.validate_candidate(pvf_with_params.clone(), timeout, params.encode()).await;
// If we get an AmbiguousWorkerDeath error, retry once after a brief delay, on the
// assumption that the conditions that caused this error may have been transient. Note that
@@ -643,19 +699,23 @@ trait ValidationBackend {
gum::warn!(
target: LOG_TARGET,
?pvf,
?pvf_with_params,
"Re-trying failed candidate validation due to AmbiguousWorkerDeath."
);
// Encode the params again when re-trying. We expect the retry case to be relatively
// rare, and we want to avoid unconditionally cloning data.
validation_result = self.validate_candidate(pvf, timeout, params.encode()).await;
validation_result =
self.validate_candidate(pvf_with_params, timeout, params.encode()).await;
}
validation_result
}
async fn precheck_pvf(&mut self, pvf: Pvf) -> Result<PrepareStats, PrepareError>;
async fn precheck_pvf(
&mut self,
pvf_with_params: PvfWithExecutorParams,
) -> Result<PrepareStats, PrepareError>;
}
#[async_trait]
@@ -663,14 +723,16 @@ impl ValidationBackend for ValidationHost {
/// Tries executing a PVF a single time (no retries).
async fn validate_candidate(
&mut self,
pvf: Pvf,
pvf_with_params: PvfWithExecutorParams,
timeout: Duration,
encoded_params: Vec<u8>,
) -> Result<WasmValidationResult, ValidationError> {
let priority = polkadot_node_core_pvf::Priority::Normal;
let (tx, rx) = oneshot::channel();
if let Err(err) = self.execute_pvf(pvf, timeout, encoded_params, priority, tx).await {
if let Err(err) =
self.execute_pvf(pvf_with_params, timeout, encoded_params, priority, tx).await
{
return Err(ValidationError::InternalError(format!(
"cannot send pvf to the validation host: {:?}",
err
@@ -681,9 +743,12 @@ impl ValidationBackend for ValidationHost {
.map_err(|_| ValidationError::InternalError("validation was cancelled".into()))?
}
async fn precheck_pvf(&mut self, pvf: Pvf) -> Result<PrepareStats, PrepareError> {
async fn precheck_pvf(
&mut self,
pvf_with_params: PvfWithExecutorParams,
) -> Result<PrepareStats, PrepareError> {
let (tx, rx) = oneshot::channel();
if let Err(err) = self.precheck_pvf(pvf, tx).await {
if let Err(err) = self.precheck_pvf(pvf_with_params, tx).await {
// Return an IO error if there was an error communicating with the host.
return Err(PrepareError::IoErr(err))
}
@@ -26,6 +26,37 @@ use polkadot_primitives::{HeadData, Id as ParaId, UpwardMessage};
use sp_core::testing::TaskExecutor;
use sp_keyring::Sr25519Keyring;
fn test_with_executor_params<T: futures::Future<Output = R>, R, M>(
mut ctx_handle: test_helpers::TestSubsystemContextHandle<M>,
test: impl FnOnce() -> T,
) -> R {
let test_fut = test();
let overseer = async move {
assert_matches!(
ctx_handle.recv().await,
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
) => {
tx.send(Ok(1u32.into())).unwrap();
}
);
assert_matches!(
ctx_handle.recv().await,
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(_, tx))
) => {
tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
}
);
};
futures::pin_mut!(test_fut);
futures::pin_mut!(overseer);
let v = executor::block_on(future::join(test_fut, overseer));
v.0
}
#[test]
fn correctly_checks_included_assumption() {
let validation_data: PersistedValidationData = Default::default();
@@ -365,7 +396,7 @@ impl MockValidateCandidateBackend {
impl ValidationBackend for MockValidateCandidateBackend {
async fn validate_candidate(
&mut self,
_pvf: Pvf,
_pvf_with_params: PvfWithExecutorParams,
_timeout: Duration,
_encoded_params: Vec<u8>,
) -> Result<WasmValidationResult, ValidationError> {
@@ -377,7 +408,10 @@ impl ValidationBackend for MockValidateCandidateBackend {
result
}
async fn precheck_pvf(&mut self, _pvf: Pvf) -> Result<PrepareStats, PrepareError> {
async fn precheck_pvf(
&mut self,
_pvf_with_params: PvfWithExecutorParams,
) -> Result<PrepareStats, PrepareError> {
unreachable!()
}
}
@@ -429,15 +463,23 @@ fn candidate_validation_ok_is_ok() {
let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() };
let v = executor::block_on(validate_candidate_exhaustive(
MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
validation_data.clone(),
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&Default::default(),
))
let pool = TaskExecutor::new();
let (mut ctx, ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let metrics = Metrics::default();
let v = test_with_executor_params(ctx_handle, || {
validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
validation_data.clone(),
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&metrics,
)
})
.unwrap();
assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => {
@@ -478,20 +520,27 @@ fn candidate_validation_bad_return_is_invalid() {
let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
let v = executor::block_on(validate_candidate_exhaustive(
MockValidateCandidateBackend::with_hardcoded_result(Err(
ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
)),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&Default::default(),
))
.unwrap();
let pool = TaskExecutor::new();
let (mut ctx, ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let metrics = Metrics::default();
assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::Timeout));
let v = test_with_executor_params(ctx_handle, || {
validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result(Err(
ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
)),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&metrics,
)
});
assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout)));
}
#[test]
@@ -541,18 +590,26 @@ fn candidate_validation_one_ambiguous_error_is_valid() {
let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() };
let v = executor::block_on(validate_candidate_exhaustive(
MockValidateCandidateBackend::with_hardcoded_result_list(vec![
Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
Ok(validation_result),
]),
validation_data.clone(),
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&Default::default(),
))
let pool = TaskExecutor::new();
let (mut ctx, ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let metrics = Metrics::default();
let v = test_with_executor_params(ctx_handle, || {
validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result_list(vec![
Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
Ok(validation_result),
]),
validation_data.clone(),
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&metrics,
)
})
.unwrap();
assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => {
@@ -593,18 +650,26 @@ fn candidate_validation_multiple_ambiguous_errors_is_invalid() {
let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
let v = executor::block_on(validate_candidate_exhaustive(
MockValidateCandidateBackend::with_hardcoded_result_list(vec![
Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
]),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&Default::default(),
))
let pool = TaskExecutor::new();
let (mut ctx, ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let metrics = Metrics::default();
let v = test_with_executor_params(ctx_handle, || {
validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result_list(vec![
Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
]),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&metrics,
)
})
.unwrap();
assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::ExecutionError(_)));
@@ -638,17 +703,25 @@ fn candidate_validation_timeout_is_internal_error() {
let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
let v = executor::block_on(validate_candidate_exhaustive(
MockValidateCandidateBackend::with_hardcoded_result(Err(
ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
)),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&Default::default(),
));
let pool = TaskExecutor::new();
let (mut ctx, ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let metrics = Metrics::default();
let v = test_with_executor_params(ctx_handle, || {
validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result(Err(
ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
)),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&metrics,
)
});
assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout)));
}
@@ -684,15 +757,23 @@ fn candidate_validation_commitment_hash_mismatch_is_invalid() {
hrmp_watermark: 12345,
};
let result = executor::block_on(validate_candidate_exhaustive(
MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&Default::default(),
))
let pool = TaskExecutor::new();
let (mut ctx, ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let metrics = Metrics::default();
let result = test_with_executor_params(ctx_handle, || {
validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&metrics,
)
})
.unwrap();
// Ensure `post validation` check on the commitments hash works as expected.
@@ -727,7 +808,12 @@ fn candidate_validation_code_mismatch_is_invalid() {
let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
let pool = TaskExecutor::new();
let (mut ctx, _ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let v = executor::block_on(validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result(Err(
ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
)),
@@ -785,15 +871,23 @@ fn compressed_code_works() {
let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() };
let v = executor::block_on(validate_candidate_exhaustive(
MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&Default::default(),
));
let pool = TaskExecutor::new();
let (mut ctx, ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let metrics = Metrics::default();
let v = test_with_executor_params(ctx_handle, || {
validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
validation_data,
validation_code,
candidate_receipt,
Arc::new(pov),
Duration::from_secs(0),
&metrics,
)
});
assert_matches!(v, Ok(ValidationResult::Valid(_, _)));
}
@@ -832,7 +926,12 @@ fn code_decompression_failure_is_error() {
let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
let pool = TaskExecutor::new();
let (mut ctx, _ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let v = executor::block_on(validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
validation_data,
validation_code,
@@ -880,7 +979,12 @@ fn pov_decompression_failure_is_invalid() {
let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
let pool = TaskExecutor::new();
let (mut ctx, _ctx_handle) =
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
let v = executor::block_on(validate_candidate_exhaustive(
ctx.sender(),
MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
validation_data,
validation_code,
@@ -907,14 +1011,17 @@ impl MockPreCheckBackend {
impl ValidationBackend for MockPreCheckBackend {
async fn validate_candidate(
&mut self,
_pvf: Pvf,
_pvf_with_params: PvfWithExecutorParams,
_timeout: Duration,
_encoded_params: Vec<u8>,
) -> Result<WasmValidationResult, ValidationError> {
unreachable!()
}
async fn precheck_pvf(&mut self, _pvf: Pvf) -> Result<PrepareStats, PrepareError> {
async fn precheck_pvf(
&mut self,
_pvf_with_params: PvfWithExecutorParams,
) -> Result<PrepareStats, PrepareError> {
self.result.clone()
}
}
@@ -953,6 +1060,22 @@ fn precheck_works() {
let _ = tx.send(Ok(Some(validation_code.clone())));
}
);
assert_matches!(
ctx_handle.recv().await,
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
) => {
tx.send(Ok(1u32.into())).unwrap();
}
);
assert_matches!(
ctx_handle.recv().await,
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(_, tx))
) => {
tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
}
);
assert_matches!(check_result.await, PreCheckOutcome::Valid);
};
@@ -999,6 +1122,22 @@ fn precheck_invalid_pvf_blob_compression() {
let _ = tx.send(Ok(Some(validation_code.clone())));
}
);
assert_matches!(
ctx_handle.recv().await,
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
) => {
tx.send(Ok(1u32.into())).unwrap();
}
);
assert_matches!(
ctx_handle.recv().await,
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(_, tx))
) => {
tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
}
);
assert_matches!(check_result.await, PreCheckOutcome::Invalid);
};
@@ -1041,6 +1180,22 @@ fn precheck_properly_classifies_outcomes() {
let _ = tx.send(Ok(Some(validation_code.clone())));
}
);
assert_matches!(
ctx_handle.recv().await,
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
) => {
tx.send(Ok(1u32.into())).unwrap();
}
);
assert_matches!(
ctx_handle.recv().await,
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(_, tx))
) => {
tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
}
);
assert_eq!(check_result.await, precheck_outcome);
};