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

Commit 8988cef

Browse files
committed
Add pre-check tests
1 parent 302e423 commit 8988cef

File tree

2 files changed

+164
-1
lines changed

2 files changed

+164
-1
lines changed

node/core/candidate-validation/src/tests.rs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,3 +631,166 @@ fn pov_decompression_failure_is_invalid() {
631631

632632
assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::PoVDecompressionFailure)));
633633
}
634+
635+
struct MockPreCheckBackend {
636+
result: Result<(), PrepareError>,
637+
}
638+
639+
impl MockPreCheckBackend {
640+
fn with_hardcoded_result(result: Result<(), PrepareError>) -> Self {
641+
Self { result }
642+
}
643+
}
644+
645+
#[async_trait]
646+
impl ValidationBackend for MockPreCheckBackend {
647+
async fn validate_candidate(
648+
&mut self,
649+
_raw_validation_code: Vec<u8>,
650+
_timeout: Duration,
651+
_params: ValidationParams,
652+
) -> Result<WasmValidationResult, ValidationError> {
653+
unreachable!()
654+
}
655+
656+
async fn precheck_pvf(&mut self, _pvf: Pvf) -> Result<(), PrepareError> {
657+
self.result.clone()
658+
}
659+
}
660+
661+
#[test]
662+
fn precheck_works() {
663+
let relay_parent = [3; 32].into();
664+
let validation_code = ValidationCode(vec![3; 16]);
665+
let validation_code_hash = validation_code.hash();
666+
667+
let pool = TaskExecutor::new();
668+
let (mut ctx, mut ctx_handle) =
669+
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
670+
671+
let (check_fut, check_result) = precheck_pvf(
672+
ctx.sender(),
673+
MockPreCheckBackend::with_hardcoded_result(Ok(())),
674+
relay_parent,
675+
validation_code_hash,
676+
)
677+
.remote_handle();
678+
679+
let test_fut = async move {
680+
assert_matches!(
681+
ctx_handle.recv().await,
682+
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
683+
rp,
684+
RuntimeApiRequest::ValidationCodeByHash(
685+
vch,
686+
tx
687+
),
688+
)) => {
689+
assert_eq!(vch, validation_code_hash);
690+
assert_eq!(rp, relay_parent);
691+
692+
let _ = tx.send(Ok(Some(validation_code.clone())));
693+
}
694+
);
695+
assert_matches!(check_result.await, PreCheckOutcome::Valid);
696+
};
697+
698+
let test_fut = future::join(test_fut, check_fut);
699+
executor::block_on(test_fut);
700+
}
701+
702+
#[test]
703+
fn precheck_invalid_pvf_blob_compression() {
704+
let relay_parent = [3; 32].into();
705+
706+
let raw_code = vec![2u8; VALIDATION_CODE_BOMB_LIMIT + 1];
707+
let validation_code =
708+
sp_maybe_compressed_blob::compress(&raw_code, VALIDATION_CODE_BOMB_LIMIT + 1)
709+
.map(ValidationCode)
710+
.unwrap();
711+
let validation_code_hash = validation_code.hash();
712+
713+
let pool = TaskExecutor::new();
714+
let (mut ctx, mut ctx_handle) =
715+
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
716+
717+
let (check_fut, check_result) = precheck_pvf(
718+
ctx.sender(),
719+
MockPreCheckBackend::with_hardcoded_result(Ok(())),
720+
relay_parent,
721+
validation_code_hash,
722+
)
723+
.remote_handle();
724+
725+
let test_fut = async move {
726+
assert_matches!(
727+
ctx_handle.recv().await,
728+
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
729+
rp,
730+
RuntimeApiRequest::ValidationCodeByHash(
731+
vch,
732+
tx
733+
),
734+
)) => {
735+
assert_eq!(vch, validation_code_hash);
736+
assert_eq!(rp, relay_parent);
737+
738+
let _ = tx.send(Ok(Some(validation_code.clone())));
739+
}
740+
);
741+
assert_matches!(check_result.await, PreCheckOutcome::Invalid);
742+
};
743+
744+
let test_fut = future::join(test_fut, check_fut);
745+
executor::block_on(test_fut);
746+
}
747+
748+
#[test]
749+
fn precheck_properly_classifies_outcomes() {
750+
let inner = |prepare_result, precheck_outcome| {
751+
let relay_parent = [3; 32].into();
752+
let validation_code = ValidationCode(vec![3; 16]);
753+
let validation_code_hash = validation_code.hash();
754+
755+
let pool = TaskExecutor::new();
756+
let (mut ctx, mut ctx_handle) =
757+
test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
758+
759+
let (check_fut, check_result) = precheck_pvf(
760+
ctx.sender(),
761+
MockPreCheckBackend::with_hardcoded_result(prepare_result),
762+
relay_parent,
763+
validation_code_hash,
764+
)
765+
.remote_handle();
766+
767+
let test_fut = async move {
768+
assert_matches!(
769+
ctx_handle.recv().await,
770+
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
771+
rp,
772+
RuntimeApiRequest::ValidationCodeByHash(
773+
vch,
774+
tx
775+
),
776+
)) => {
777+
assert_eq!(vch, validation_code_hash);
778+
assert_eq!(rp, relay_parent);
779+
780+
let _ = tx.send(Ok(Some(validation_code.clone())));
781+
}
782+
);
783+
assert_eq!(check_result.await, precheck_outcome);
784+
};
785+
786+
let test_fut = future::join(test_fut, check_fut);
787+
executor::block_on(test_fut);
788+
};
789+
790+
inner(Err(PrepareError::Prevalidation("foo".to_owned())), PreCheckOutcome::Invalid);
791+
inner(Err(PrepareError::Preparation("bar".to_owned())), PreCheckOutcome::Invalid);
792+
inner(Err(PrepareError::Panic("baz".to_owned())), PreCheckOutcome::Invalid);
793+
794+
inner(Err(PrepareError::TimedOut), PreCheckOutcome::Failed);
795+
inner(Err(PrepareError::DidNotMakeIt), PreCheckOutcome::Failed);
796+
}

node/subsystem-types/src/messages.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ impl BoundToRelayParent for CandidateBackingMessage {
9494
pub struct ValidationFailed(pub String);
9595

9696
/// The outcome of the candidate-validation's PVF pre-check request.
97-
#[derive(Debug)]
97+
#[derive(Debug, PartialEq)]
9898
pub enum PreCheckOutcome {
9999
/// The PVF has been compiled successfully within the given constraints.
100100
Valid,

0 commit comments

Comments
 (0)