24
24
#![ warn( missing_docs) ]
25
25
26
26
use polkadot_node_core_pvf:: {
27
- InvalidCandidate as WasmInvalidCandidate , PrepareError , PrepareStats , PvfWithExecutorParams ,
27
+ InvalidCandidate as WasmInvalidCandidate , PrepareError , PrepareStats , PvfPrepData ,
28
28
ValidationError , ValidationHost ,
29
29
} ;
30
30
use polkadot_node_primitives:: {
@@ -43,7 +43,8 @@ use polkadot_node_subsystem_util::executor_params_at_relay_parent;
43
43
use polkadot_parachain:: primitives:: { ValidationParams , ValidationResult as WasmValidationResult } ;
44
44
use polkadot_primitives:: {
45
45
vstaging:: ExecutorParams , CandidateCommitments , CandidateDescriptor , CandidateReceipt , Hash ,
46
- OccupiedCoreAssumption , PersistedValidationData , ValidationCode , ValidationCodeHash ,
46
+ OccupiedCoreAssumption , PersistedValidationData , PvfExecTimeoutKind , PvfPrepTimeoutKind ,
47
+ ValidationCode , ValidationCodeHash ,
47
48
} ;
48
49
49
50
use parity_scale_codec:: Encode ;
@@ -68,6 +69,13 @@ const PVF_EXECUTION_RETRY_DELAY: Duration = Duration::from_secs(3);
68
69
#[ cfg( test) ]
69
70
const PVF_EXECUTION_RETRY_DELAY : Duration = Duration :: from_millis ( 200 ) ;
70
71
72
+ // Default PVF timeouts. Must never be changed! Use executor environment parameters in
73
+ // `session_info` pallet to adjust them. See also `PvfTimeoutKind` docs.
74
+ const DEFAULT_PRECHECK_PREPARATION_TIMEOUT : Duration = Duration :: from_secs ( 60 ) ;
75
+ const DEFAULT_LENIENT_PREPARATION_TIMEOUT : Duration = Duration :: from_secs ( 360 ) ;
76
+ const DEFAULT_BACKING_EXECUTION_TIMEOUT : Duration = Duration :: from_secs ( 2 ) ;
77
+ const DEFAULT_APPROVAL_EXECUTION_TIMEOUT : Duration = Duration :: from_secs ( 12 ) ;
78
+
71
79
/// Configuration for the candidate validation subsystem
72
80
#[ derive( Clone ) ]
73
81
pub struct Config {
@@ -330,18 +338,20 @@ where
330
338
return PreCheckOutcome :: Invalid
331
339
} ;
332
340
333
- let pvf_with_params = match sp_maybe_compressed_blob:: decompress (
341
+ let timeout = pvf_prep_timeout ( & executor_params, PvfPrepTimeoutKind :: Precheck ) ;
342
+
343
+ let pvf = match sp_maybe_compressed_blob:: decompress (
334
344
& validation_code. 0 ,
335
345
VALIDATION_CODE_BOMB_LIMIT ,
336
346
) {
337
- Ok ( code) => PvfWithExecutorParams :: from_code ( code. into_owned ( ) , executor_params) ,
347
+ Ok ( code) => PvfPrepData :: from_code ( code. into_owned ( ) , executor_params, timeout ) ,
338
348
Err ( e) => {
339
349
gum:: debug!( target: LOG_TARGET , err=?e, "precheck: cannot decompress validation code" ) ;
340
350
return PreCheckOutcome :: Invalid
341
351
} ,
342
352
} ;
343
353
344
- match validation_backend. precheck_pvf ( pvf_with_params ) . await {
354
+ match validation_backend. precheck_pvf ( pvf ) . await {
345
355
Ok ( _) => PreCheckOutcome :: Valid ,
346
356
Err ( prepare_err) =>
347
357
if prepare_err. is_deterministic ( ) {
@@ -465,7 +475,7 @@ async fn validate_from_chain_state<Sender>(
465
475
validation_host : ValidationHost ,
466
476
candidate_receipt : CandidateReceipt ,
467
477
pov : Arc < PoV > ,
468
- timeout : Duration ,
478
+ exec_timeout_kind : PvfExecTimeoutKind ,
469
479
metrics : & Metrics ,
470
480
) -> Result < ValidationResult , ValidationFailed >
471
481
where
@@ -485,7 +495,7 @@ where
485
495
validation_code,
486
496
candidate_receipt. clone ( ) ,
487
497
pov,
488
- timeout ,
498
+ exec_timeout_kind ,
489
499
metrics,
490
500
)
491
501
. await ;
@@ -521,7 +531,7 @@ async fn validate_candidate_exhaustive<Sender>(
521
531
validation_code : ValidationCode ,
522
532
candidate_receipt : CandidateReceipt ,
523
533
pov : Arc < PoV > ,
524
- timeout : Duration ,
534
+ exec_timeout_kind : PvfExecTimeoutKind ,
525
535
metrics : & Metrics ,
526
536
) -> Result < ValidationResult , ValidationFailed >
527
537
where
@@ -606,7 +616,7 @@ where
606
616
let result = validation_backend
607
617
. validate_candidate_with_retry (
608
618
raw_validation_code. to_vec ( ) ,
609
- timeout ,
619
+ pvf_exec_timeout ( & executor_params , exec_timeout_kind ) ,
610
620
params,
611
621
executor_params,
612
622
)
@@ -667,8 +677,8 @@ trait ValidationBackend {
667
677
/// Tries executing a PVF a single time (no retries).
668
678
async fn validate_candidate (
669
679
& mut self ,
670
- pvf_with_params : PvfWithExecutorParams ,
671
- timeout : Duration ,
680
+ pvf : PvfPrepData ,
681
+ exec_timeout : Duration ,
672
682
encoded_params : Vec < u8 > ,
673
683
) -> Result < WasmValidationResult , ValidationError > ;
674
684
@@ -677,16 +687,16 @@ trait ValidationBackend {
677
687
async fn validate_candidate_with_retry (
678
688
& mut self ,
679
689
raw_validation_code : Vec < u8 > ,
680
- timeout : Duration ,
690
+ exec_timeout : Duration ,
681
691
params : ValidationParams ,
682
692
executor_params : ExecutorParams ,
683
693
) -> Result < WasmValidationResult , ValidationError > {
684
694
// Construct the PVF a single time, since it is an expensive operation. Cloning it is cheap.
685
- let pvf_with_params =
686
- PvfWithExecutorParams :: from_code ( raw_validation_code, executor_params) ;
695
+ let prep_timeout = pvf_prep_timeout ( & executor_params , PvfPrepTimeoutKind :: Lenient ) ;
696
+ let pvf = PvfPrepData :: from_code ( raw_validation_code, executor_params, prep_timeout ) ;
687
697
688
698
let mut validation_result =
689
- self . validate_candidate ( pvf_with_params . clone ( ) , timeout , params. encode ( ) ) . await ;
699
+ self . validate_candidate ( pvf . clone ( ) , exec_timeout , params. encode ( ) ) . await ;
690
700
691
701
// If we get an AmbiguousWorkerDeath error, retry once after a brief delay, on the
692
702
// assumption that the conditions that caused this error may have been transient. Note that
@@ -699,40 +709,34 @@ trait ValidationBackend {
699
709
700
710
gum:: warn!(
701
711
target: LOG_TARGET ,
702
- ?pvf_with_params ,
712
+ ?pvf ,
703
713
"Re-trying failed candidate validation due to AmbiguousWorkerDeath."
704
714
) ;
705
715
706
716
// Encode the params again when re-trying. We expect the retry case to be relatively
707
717
// rare, and we want to avoid unconditionally cloning data.
708
- validation_result =
709
- self . validate_candidate ( pvf_with_params, timeout, params. encode ( ) ) . await ;
718
+ validation_result = self . validate_candidate ( pvf, exec_timeout, params. encode ( ) ) . await ;
710
719
}
711
720
712
721
validation_result
713
722
}
714
723
715
- async fn precheck_pvf (
716
- & mut self ,
717
- pvf_with_params : PvfWithExecutorParams ,
718
- ) -> Result < PrepareStats , PrepareError > ;
724
+ async fn precheck_pvf ( & mut self , pvf : PvfPrepData ) -> Result < PrepareStats , PrepareError > ;
719
725
}
720
726
721
727
#[ async_trait]
722
728
impl ValidationBackend for ValidationHost {
723
729
/// Tries executing a PVF a single time (no retries).
724
730
async fn validate_candidate (
725
731
& mut self ,
726
- pvf_with_params : PvfWithExecutorParams ,
727
- timeout : Duration ,
732
+ pvf : PvfPrepData ,
733
+ exec_timeout : Duration ,
728
734
encoded_params : Vec < u8 > ,
729
735
) -> Result < WasmValidationResult , ValidationError > {
730
736
let priority = polkadot_node_core_pvf:: Priority :: Normal ;
731
737
732
738
let ( tx, rx) = oneshot:: channel ( ) ;
733
- if let Err ( err) =
734
- self . execute_pvf ( pvf_with_params, timeout, encoded_params, priority, tx) . await
735
- {
739
+ if let Err ( err) = self . execute_pvf ( pvf, exec_timeout, encoded_params, priority, tx) . await {
736
740
return Err ( ValidationError :: InternalError ( format ! (
737
741
"cannot send pvf to the validation host: {:?}" ,
738
742
err
@@ -743,12 +747,9 @@ impl ValidationBackend for ValidationHost {
743
747
. map_err ( |_| ValidationError :: InternalError ( "validation was cancelled" . into ( ) ) ) ?
744
748
}
745
749
746
- async fn precheck_pvf (
747
- & mut self ,
748
- pvf_with_params : PvfWithExecutorParams ,
749
- ) -> Result < PrepareStats , PrepareError > {
750
+ async fn precheck_pvf ( & mut self , pvf : PvfPrepData ) -> Result < PrepareStats , PrepareError > {
750
751
let ( tx, rx) = oneshot:: channel ( ) ;
751
- if let Err ( err) = self . precheck_pvf ( pvf_with_params , tx) . await {
752
+ if let Err ( err) = self . precheck_pvf ( pvf , tx) . await {
752
753
// Return an IO error if there was an error communicating with the host.
753
754
return Err ( PrepareError :: IoErr ( err) )
754
755
}
@@ -788,3 +789,23 @@ fn perform_basic_checks(
788
789
789
790
Ok ( ( ) )
790
791
}
792
+
793
+ fn pvf_prep_timeout ( executor_params : & ExecutorParams , kind : PvfPrepTimeoutKind ) -> Duration {
794
+ if let Some ( timeout) = executor_params. pvf_prep_timeout ( kind) {
795
+ return timeout
796
+ }
797
+ match kind {
798
+ PvfPrepTimeoutKind :: Precheck => DEFAULT_PRECHECK_PREPARATION_TIMEOUT ,
799
+ PvfPrepTimeoutKind :: Lenient => DEFAULT_LENIENT_PREPARATION_TIMEOUT ,
800
+ }
801
+ }
802
+
803
+ fn pvf_exec_timeout ( executor_params : & ExecutorParams , kind : PvfExecTimeoutKind ) -> Duration {
804
+ if let Some ( timeout) = executor_params. pvf_exec_timeout ( kind) {
805
+ return timeout
806
+ }
807
+ match kind {
808
+ PvfExecTimeoutKind :: Backing => DEFAULT_BACKING_EXECUTION_TIMEOUT ,
809
+ PvfExecTimeoutKind :: Approval => DEFAULT_APPROVAL_EXECUTION_TIMEOUT ,
810
+ }
811
+ }
0 commit comments