1use alloc::{
19 vec,
20 vec::{IntoIter, Vec},
21};
22use bitvec::{field::BitField, slice::BitSlice, vec::BitVec};
23use codec::{Decode, Encode};
24use core::{
25 marker::PhantomData,
26 slice::{Iter, IterMut},
27};
28use scale_info::TypeInfo;
29
30use sp_application_crypto::KeyTypeId;
31use sp_arithmetic::{
32 traits::{BaseArithmetic, Saturating},
33 Perbill,
34};
35use sp_core::RuntimeDebug;
36use sp_inherents::InherentIdentifier;
37use sp_runtime::traits::{AppVerify, Header as HeaderT};
38
39pub use sp_runtime::traits::{BlakeTwo256, Hash as HashT};
40
41pub use polkadot_core_primitives::v2::{
43 AccountId, AccountIndex, AccountPublic, Balance, Block, BlockId, BlockNumber, CandidateHash,
44 ChainId, DownwardMessage, Hash, Header, InboundDownwardMessage, InboundHrmpMessage, Moment,
45 Nonce, OutboundHrmpMessage, Remark, Signature, UncheckedExtrinsic,
46};
47
48pub use polkadot_parachain_primitives::primitives::{
50 HeadData, HorizontalMessages, HrmpChannelId, Id, UpwardMessage, UpwardMessages, ValidationCode,
51 ValidationCodeHash, LOWEST_PUBLIC_ID,
52};
53
54use serde::{Deserialize, Serialize};
55
56pub use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
57pub use sp_consensus_slots::Slot;
58pub use sp_staking::SessionIndex;
59
60mod signed;
62pub use signed::{EncodeAs, Signed, UncheckedSigned};
63
64pub mod async_backing;
65pub mod executor_params;
66pub mod slashing;
67
68pub use async_backing::AsyncBackingParams;
69pub use executor_params::{
70 ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, ExecutorParamsPrepHash,
71};
72
73mod metrics;
74pub use metrics::{
75 metric_definitions, RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues,
76 RuntimeMetricLabels, RuntimeMetricOp, RuntimeMetricUpdate,
77};
78
79pub const COLLATOR_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"coll");
81const LOG_TARGET: &str = "runtime::primitives";
82
83mod collator_app {
84 use sp_application_crypto::{app_crypto, sr25519};
85 app_crypto!(sr25519, super::COLLATOR_KEY_TYPE_ID);
86}
87
88pub type CollatorId = collator_app::Public;
90
91#[cfg(feature = "std")]
93pub type CollatorPair = collator_app::Pair;
94
95pub type CollatorSignature = collator_app::Signature;
97
98pub const PARACHAIN_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"para");
100
101mod validator_app {
102 use sp_application_crypto::{app_crypto, sr25519};
103 app_crypto!(sr25519, super::PARACHAIN_KEY_TYPE_ID);
104}
105
106pub type ValidatorId = validator_app::Public;
111
112pub trait TypeIndex {
114 fn type_index(&self) -> usize;
116}
117
118#[derive(Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
121#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))]
122pub struct ValidatorIndex(pub u32);
123
124#[derive(Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
131#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))]
132pub struct ChunkIndex(pub u32);
133
134impl From<ChunkIndex> for ValidatorIndex {
135 fn from(c_index: ChunkIndex) -> Self {
136 ValidatorIndex(c_index.0)
137 }
138}
139
140impl From<ValidatorIndex> for ChunkIndex {
141 fn from(v_index: ValidatorIndex) -> Self {
142 ChunkIndex(v_index.0)
143 }
144}
145
146impl From<u32> for ChunkIndex {
147 fn from(n: u32) -> Self {
148 ChunkIndex(n)
149 }
150}
151
152impl From<u32> for ValidatorIndex {
154 fn from(n: u32) -> Self {
155 ValidatorIndex(n)
156 }
157}
158
159impl TypeIndex for ValidatorIndex {
160 fn type_index(&self) -> usize {
161 self.0 as usize
162 }
163}
164
165sp_application_crypto::with_pair! {
166 pub type ValidatorPair = validator_app::Pair;
168}
169
170pub type ValidatorSignature = validator_app::Signature;
175
176pub mod well_known_keys {
178 use super::{HrmpChannelId, Id, WellKnownKey};
179 use alloc::vec::Vec;
180 use codec::Encode as _;
181 use hex_literal::hex;
182 use sp_io::hashing::twox_64;
183
184 pub const EPOCH_INDEX: &[u8] =
200 &hex!["1cb6f36e027abb2091cfb5110ab5087f38316cbf8fa0da822a20ac1c55bf1be3"];
201
202 pub const CURRENT_BLOCK_RANDOMNESS: &[u8] =
206 &hex!["1cb6f36e027abb2091cfb5110ab5087fd077dfdb8adb10f78f10a5df8742c545"];
207
208 pub const ONE_EPOCH_AGO_RANDOMNESS: &[u8] =
212 &hex!["1cb6f36e027abb2091cfb5110ab5087f7ce678799d3eff024253b90e84927cc6"];
213
214 pub const TWO_EPOCHS_AGO_RANDOMNESS: &[u8] =
218 &hex!["1cb6f36e027abb2091cfb5110ab5087f7a414cb008e0e61e46722aa60abdd672"];
219
220 pub const CURRENT_SLOT: &[u8] =
224 &hex!["1cb6f36e027abb2091cfb5110ab5087f06155b3cd9a8c9e5e9a23fd5dc13a5ed"];
225
226 pub const ACTIVE_CONFIG: &[u8] =
230 &hex!["06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"];
231
232 pub fn para_head(para_id: Id) -> Vec<u8> {
236 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c3"];
237
238 para_id.using_encoded(|para_id: &[u8]| {
239 prefix
240 .as_ref()
241 .iter()
242 .chain(twox_64(para_id).iter())
243 .chain(para_id.iter())
244 .cloned()
245 .collect()
246 })
247 }
248
249 #[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
256 pub fn relay_dispatch_queue_size(para_id: Id) -> Vec<u8> {
257 let prefix = hex!["f5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e"];
258
259 para_id.using_encoded(|para_id: &[u8]| {
260 prefix
261 .as_ref()
262 .iter()
263 .chain(twox_64(para_id).iter())
264 .chain(para_id.iter())
265 .cloned()
266 .collect()
267 })
268 }
269
270 #[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
272 pub fn relay_dispatch_queue_size_typed(para: Id) -> WellKnownKey<(u32, u32)> {
273 #[allow(deprecated)]
274 relay_dispatch_queue_size(para).into()
275 }
276
277 pub fn relay_dispatch_queue_remaining_capacity(para_id: Id) -> WellKnownKey<(u32, u32)> {
285 (b":relay_dispatch_queue_remaining_capacity", para_id).encode().into()
286 }
287
288 pub fn hrmp_channels(channel: HrmpChannelId) -> Vec<u8> {
292 let prefix = hex!["6a0da05ca59913bc38a8630590f2627cb6604cff828a6e3f579ca6c59ace013d"];
293
294 channel.using_encoded(|channel: &[u8]| {
295 prefix
296 .as_ref()
297 .iter()
298 .chain(twox_64(channel).iter())
299 .chain(channel.iter())
300 .cloned()
301 .collect()
302 })
303 }
304
305 pub fn hrmp_ingress_channel_index(para_id: Id) -> Vec<u8> {
309 let prefix = hex!["6a0da05ca59913bc38a8630590f2627c1d3719f5b0b12c7105c073c507445948"];
310
311 para_id.using_encoded(|para_id: &[u8]| {
312 prefix
313 .as_ref()
314 .iter()
315 .chain(twox_64(para_id).iter())
316 .chain(para_id.iter())
317 .cloned()
318 .collect()
319 })
320 }
321
322 pub fn hrmp_egress_channel_index(para_id: Id) -> Vec<u8> {
326 let prefix = hex!["6a0da05ca59913bc38a8630590f2627cf12b746dcf32e843354583c9702cc020"];
327
328 para_id.using_encoded(|para_id: &[u8]| {
329 prefix
330 .as_ref()
331 .iter()
332 .chain(twox_64(para_id).iter())
333 .chain(para_id.iter())
334 .cloned()
335 .collect()
336 })
337 }
338
339 pub fn dmq_mqc_head(para_id: Id) -> Vec<u8> {
344 let prefix = hex!["63f78c98723ddc9073523ef3beefda0c4d7fefc408aac59dbfe80a72ac8e3ce5"];
345
346 para_id.using_encoded(|para_id: &[u8]| {
347 prefix
348 .as_ref()
349 .iter()
350 .chain(twox_64(para_id).iter())
351 .chain(para_id.iter())
352 .cloned()
353 .collect()
354 })
355 }
356
357 pub fn upgrade_go_ahead_signal(para_id: Id) -> Vec<u8> {
362 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1949e94c040f5e73d9b7addd6cb603d15d3"];
363
364 para_id.using_encoded(|para_id: &[u8]| {
365 prefix
366 .as_ref()
367 .iter()
368 .chain(twox_64(para_id).iter())
369 .chain(para_id.iter())
370 .cloned()
371 .collect()
372 })
373 }
374
375 pub fn upgrade_restriction_signal(para_id: Id) -> Vec<u8> {
380 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa194f27bbb460270642b5bcaf032ea04d56a"];
381
382 para_id.using_encoded(|para_id: &[u8]| {
383 prefix
384 .as_ref()
385 .iter()
386 .chain(twox_64(para_id).iter())
387 .chain(para_id.iter())
388 .cloned()
389 .collect()
390 })
391 }
392}
393
394pub const PARACHAINS_INHERENT_IDENTIFIER: InherentIdentifier = *b"parachn0";
396
397pub const ASSIGNMENT_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"asgn");
399
400pub const MIN_CODE_SIZE: u32 = 9;
402
403pub const MAX_CODE_SIZE: u32 = 3 * 1024 * 1024;
413
414pub const MAX_HEAD_DATA_SIZE: u32 = 1 * 1024 * 1024;
421
422pub const MAX_POV_SIZE: u32 = 5 * 1024 * 1024;
430
431pub const ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE: u32 = 10_000;
435
436pub const ON_DEMAND_MAX_QUEUE_MAX_SIZE: u32 = 1_000_000_000;
442
443pub const LEGACY_MIN_BACKING_VOTES: u32 = 2;
446
447mod assignment_app {
450 use sp_application_crypto::{app_crypto, sr25519};
451 app_crypto!(sr25519, super::ASSIGNMENT_KEY_TYPE_ID);
452}
453
454pub type AssignmentId = assignment_app::Public;
457
458sp_application_crypto::with_pair! {
459 pub type AssignmentPair = assignment_app::Pair;
462}
463
464pub type CandidateIndex = u32;
466
467pub fn collator_signature_payload<H: AsRef<[u8]>>(
469 relay_parent: &H,
470 para_id: &Id,
471 persisted_validation_data_hash: &Hash,
472 pov_hash: &Hash,
473 validation_code_hash: &ValidationCodeHash,
474) -> [u8; 132] {
475 let mut payload = [0u8; 132];
477
478 payload[0..32].copy_from_slice(relay_parent.as_ref());
479 u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s));
480 payload[36..68].copy_from_slice(persisted_validation_data_hash.as_ref());
481 payload[68..100].copy_from_slice(pov_hash.as_ref());
482 payload[100..132].copy_from_slice(validation_code_hash.as_ref());
483
484 payload
485}
486
487fn check_collator_signature<H: AsRef<[u8]>>(
488 relay_parent: &H,
489 para_id: &Id,
490 persisted_validation_data_hash: &Hash,
491 pov_hash: &Hash,
492 validation_code_hash: &ValidationCodeHash,
493 collator: &CollatorId,
494 signature: &CollatorSignature,
495) -> Result<(), ()> {
496 let payload = collator_signature_payload(
497 relay_parent,
498 para_id,
499 persisted_validation_data_hash,
500 pov_hash,
501 validation_code_hash,
502 );
503
504 if signature.verify(&payload[..], collator) {
505 Ok(())
506 } else {
507 Err(())
508 }
509}
510
511#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
513#[cfg_attr(feature = "std", derive(Hash))]
514pub struct CandidateDescriptor<H = Hash> {
515 pub para_id: Id,
517 pub relay_parent: H,
519 pub collator: CollatorId,
521 pub persisted_validation_data_hash: Hash,
525 pub pov_hash: Hash,
527 pub erasure_root: Hash,
529 pub signature: CollatorSignature,
532 pub para_head: Hash,
534 pub validation_code_hash: ValidationCodeHash,
536}
537
538impl<H: AsRef<[u8]>> CandidateDescriptor<H> {
539 pub fn check_collator_signature(&self) -> Result<(), ()> {
541 check_collator_signature(
542 &self.relay_parent,
543 &self.para_id,
544 &self.persisted_validation_data_hash,
545 &self.pov_hash,
546 &self.validation_code_hash,
547 &self.collator,
548 &self.signature,
549 )
550 }
551}
552
553#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
555pub struct CandidateReceipt<H = Hash> {
556 pub descriptor: CandidateDescriptor<H>,
558 pub commitments_hash: Hash,
560}
561
562impl<H> CandidateReceipt<H> {
563 pub fn descriptor(&self) -> &CandidateDescriptor<H> {
565 &self.descriptor
566 }
567
568 pub fn hash(&self) -> CandidateHash
570 where
571 H: Encode,
572 {
573 CandidateHash(BlakeTwo256::hash_of(self))
574 }
575}
576
577#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
579#[cfg_attr(feature = "std", derive(Hash))]
580pub struct CommittedCandidateReceipt<H = Hash> {
581 pub descriptor: CandidateDescriptor<H>,
583 pub commitments: CandidateCommitments,
585}
586
587impl<H> CommittedCandidateReceipt<H> {
588 pub fn descriptor(&self) -> &CandidateDescriptor<H> {
590 &self.descriptor
591 }
592}
593
594impl<H: Clone> CommittedCandidateReceipt<H> {
595 pub fn to_plain(&self) -> CandidateReceipt<H> {
597 CandidateReceipt {
598 descriptor: self.descriptor.clone(),
599 commitments_hash: self.commitments.hash(),
600 }
601 }
602
603 pub fn hash(&self) -> CandidateHash
608 where
609 H: Encode,
610 {
611 self.to_plain().hash()
612 }
613
614 pub fn corresponds_to(&self, receipt: &CandidateReceipt<H>) -> bool
616 where
617 H: PartialEq,
618 {
619 receipt.descriptor == self.descriptor && receipt.commitments_hash == self.commitments.hash()
620 }
621}
622
623impl PartialOrd for CommittedCandidateReceipt {
624 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
625 Some(self.cmp(other))
626 }
627}
628
629impl Ord for CommittedCandidateReceipt {
630 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
631 self.descriptor()
634 .para_id
635 .cmp(&other.descriptor().para_id)
636 .then_with(|| self.commitments.head_data.cmp(&other.commitments.head_data))
637 }
638}
639
640#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
662#[cfg_attr(feature = "std", derive(Default))]
663pub struct PersistedValidationData<H = Hash, N = BlockNumber> {
664 pub parent_head: HeadData,
666 pub relay_parent_number: N,
668 pub relay_parent_storage_root: H,
670 pub max_pov_size: u32,
672}
673
674impl<H: Encode, N: Encode> PersistedValidationData<H, N> {
675 pub fn hash(&self) -> Hash {
677 BlakeTwo256::hash_of(self)
678 }
679}
680
681#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
683#[cfg_attr(feature = "std", derive(Default, Hash))]
684pub struct CandidateCommitments<N = BlockNumber> {
685 pub upward_messages: UpwardMessages,
687 pub horizontal_messages: HorizontalMessages,
689 pub new_validation_code: Option<ValidationCode>,
691 pub head_data: HeadData,
693 pub processed_downward_messages: u32,
695 pub hrmp_watermark: N,
698}
699
700impl CandidateCommitments {
701 pub fn hash(&self) -> Hash {
703 BlakeTwo256::hash_of(self)
704 }
705}
706
707#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
711pub struct AvailabilityBitfield(pub BitVec<u8, bitvec::order::Lsb0>);
712
713impl From<BitVec<u8, bitvec::order::Lsb0>> for AvailabilityBitfield {
714 fn from(inner: BitVec<u8, bitvec::order::Lsb0>) -> Self {
715 AvailabilityBitfield(inner)
716 }
717}
718
719pub type SignedStatement = Signed<CompactStatement>;
721pub type UncheckedSignedStatement = UncheckedSigned<CompactStatement>;
723
724pub type SignedAvailabilityBitfield = Signed<AvailabilityBitfield>;
726pub type UncheckedSignedAvailabilityBitfield = UncheckedSigned<AvailabilityBitfield>;
728
729pub type SignedAvailabilityBitfields = Vec<SignedAvailabilityBitfield>;
731pub type UncheckedSignedAvailabilityBitfields = Vec<UncheckedSignedAvailabilityBitfield>;
734
735#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
737pub struct BackedCandidate<H = Hash> {
738 candidate: CommittedCandidateReceipt<H>,
740 validity_votes: Vec<ValidityAttestation>,
742 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
746}
747
748impl<H> BackedCandidate<H> {
749 pub fn new(
751 candidate: CommittedCandidateReceipt<H>,
752 validity_votes: Vec<ValidityAttestation>,
753 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
754 core_index: Option<CoreIndex>,
755 ) -> Self {
756 let mut instance = Self { candidate, validity_votes, validator_indices };
757 if let Some(core_index) = core_index {
758 instance.inject_core_index(core_index);
759 }
760 instance
761 }
762
763 pub fn descriptor(&self) -> &CandidateDescriptor<H> {
765 &self.candidate.descriptor
766 }
767
768 pub fn candidate(&self) -> &CommittedCandidateReceipt<H> {
770 &self.candidate
771 }
772
773 pub fn validity_votes(&self) -> &[ValidityAttestation] {
775 &self.validity_votes
776 }
777
778 pub fn validity_votes_mut(&mut self) -> &mut Vec<ValidityAttestation> {
780 &mut self.validity_votes
781 }
782
783 pub fn hash(&self) -> CandidateHash
785 where
786 H: Clone + Encode,
787 {
788 self.candidate.hash()
789 }
790
791 pub fn receipt(&self) -> CandidateReceipt<H>
793 where
794 H: Clone,
795 {
796 self.candidate.to_plain()
797 }
798
799 pub fn validator_indices_and_core_index(
801 &self,
802 core_index_enabled: bool,
803 ) -> (&BitSlice<u8, bitvec::order::Lsb0>, Option<CoreIndex>) {
804 if core_index_enabled {
807 let core_idx_offset = self.validator_indices.len().saturating_sub(8);
808 if core_idx_offset > 0 {
809 let (validator_indices_slice, core_idx_slice) =
810 self.validator_indices.split_at(core_idx_offset);
811 return (
812 validator_indices_slice,
813 Some(CoreIndex(core_idx_slice.load::<u8>() as u32)),
814 );
815 }
816 }
817
818 (&self.validator_indices, None)
819 }
820
821 fn inject_core_index(&mut self, core_index: CoreIndex) {
823 let core_index_to_inject: BitVec<u8, bitvec::order::Lsb0> =
824 BitVec::from_vec(vec![core_index.0 as u8]);
825 self.validator_indices.extend(core_index_to_inject);
826 }
827
828 pub fn set_validator_indices_and_core_index(
830 &mut self,
831 new_indices: BitVec<u8, bitvec::order::Lsb0>,
832 maybe_core_index: Option<CoreIndex>,
833 ) {
834 self.validator_indices = new_indices;
835
836 if let Some(core_index) = maybe_core_index {
837 self.inject_core_index(core_index);
838 }
839 }
840}
841
842pub fn check_candidate_backing<H: AsRef<[u8]> + Clone + Encode + core::fmt::Debug>(
853 candidate_hash: CandidateHash,
854 validity_votes: &[ValidityAttestation],
855 validator_indices: &BitSlice<u8, bitvec::order::Lsb0>,
856 signing_context: &SigningContext<H>,
857 group_len: usize,
858 validator_lookup: impl Fn(usize) -> Option<ValidatorId>,
859) -> Result<usize, ()> {
860 if validator_indices.len() != group_len {
861 log::debug!(
862 target: LOG_TARGET,
863 "Check candidate backing: indices mismatch: group_len = {} , indices_len = {}",
864 group_len,
865 validator_indices.len(),
866 );
867 return Err(())
868 }
869
870 if validity_votes.len() > group_len {
871 log::debug!(
872 target: LOG_TARGET,
873 "Check candidate backing: Too many votes, expected: {}, found: {}",
874 group_len,
875 validity_votes.len(),
876 );
877 return Err(())
878 }
879
880 let mut signed = 0;
881 for ((val_in_group_idx, _), attestation) in validator_indices
882 .iter()
883 .enumerate()
884 .filter(|(_, signed)| **signed)
885 .zip(validity_votes.iter())
886 {
887 let validator_id = validator_lookup(val_in_group_idx).ok_or(())?;
888 let payload = attestation.signed_payload(candidate_hash, signing_context);
889 let sig = attestation.signature();
890
891 if sig.verify(&payload[..], &validator_id) {
892 signed += 1;
893 } else {
894 log::debug!(
895 target: LOG_TARGET,
896 "Check candidate backing: Invalid signature. validator_id = {:?}, validator_index = {} ",
897 validator_id,
898 val_in_group_idx,
899 );
900 return Err(())
901 }
902 }
903
904 if signed != validity_votes.len() {
905 log::error!(
906 target: LOG_TARGET,
907 "Check candidate backing: Too many signatures, expected = {}, found = {}",
908 validity_votes.len(),
909 signed,
910 );
911 return Err(())
912 }
913
914 Ok(signed)
915}
916
917#[derive(
919 Encode, Decode, Default, PartialOrd, Ord, Eq, PartialEq, Clone, Copy, TypeInfo, RuntimeDebug,
920)]
921#[cfg_attr(feature = "std", derive(Hash))]
922pub struct CoreIndex(pub u32);
923
924impl From<u32> for CoreIndex {
925 fn from(i: u32) -> CoreIndex {
926 CoreIndex(i)
927 }
928}
929
930impl TypeIndex for CoreIndex {
931 fn type_index(&self) -> usize {
932 self.0 as usize
933 }
934}
935
936#[derive(Encode, Decode, Default, Clone, Copy, Debug, PartialEq, Eq, TypeInfo, PartialOrd, Ord)]
938#[cfg_attr(feature = "std", derive(Hash))]
939pub struct GroupIndex(pub u32);
940
941impl From<u32> for GroupIndex {
942 fn from(i: u32) -> GroupIndex {
943 GroupIndex(i)
944 }
945}
946
947impl TypeIndex for GroupIndex {
948 fn type_index(&self) -> usize {
949 self.0 as usize
950 }
951}
952
953#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
955pub struct ParathreadClaim(pub Id, pub Option<CollatorId>);
956
957#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
959pub struct ParathreadEntry {
960 pub claim: ParathreadClaim,
962 pub retries: u32,
964}
965
966#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
968#[cfg_attr(feature = "std", derive(PartialEq))]
969pub struct GroupRotationInfo<N = BlockNumber> {
970 pub session_start_block: N,
972 pub group_rotation_frequency: N,
974 pub now: N,
976}
977
978impl GroupRotationInfo {
979 pub fn group_for_core(&self, core_index: CoreIndex, cores: usize) -> GroupIndex {
984 if self.group_rotation_frequency == 0 {
985 return GroupIndex(core_index.0)
986 }
987 if cores == 0 {
988 return GroupIndex(0)
989 }
990
991 let cores = core::cmp::min(cores, u32::MAX as usize);
992 let blocks_since_start = self.now.saturating_sub(self.session_start_block);
993 let rotations = blocks_since_start / self.group_rotation_frequency;
994
995 let idx = (core_index.0 as usize + rotations as usize) % cores;
998 GroupIndex(idx as u32)
999 }
1000
1001 pub fn core_for_group(&self, group_index: GroupIndex, cores: usize) -> CoreIndex {
1006 if self.group_rotation_frequency == 0 {
1007 return CoreIndex(group_index.0)
1008 }
1009 if cores == 0 {
1010 return CoreIndex(0)
1011 }
1012
1013 let cores = core::cmp::min(cores, u32::MAX as usize);
1014 let blocks_since_start = self.now.saturating_sub(self.session_start_block);
1015 let rotations = blocks_since_start / self.group_rotation_frequency;
1016 let rotations = rotations % cores as u32;
1017
1018 let idx = (group_index.0 as usize + cores - rotations as usize) % cores;
1024 CoreIndex(idx as u32)
1025 }
1026
1027 pub fn bump_rotation(&self) -> Self {
1029 GroupRotationInfo {
1030 session_start_block: self.session_start_block,
1031 group_rotation_frequency: self.group_rotation_frequency,
1032 now: self.next_rotation_at(),
1033 }
1034 }
1035}
1036
1037impl<N: Saturating + BaseArithmetic + Copy> GroupRotationInfo<N> {
1038 pub fn next_rotation_at(&self) -> N {
1041 let cycle_once = self.now + self.group_rotation_frequency;
1042 cycle_once -
1043 (cycle_once.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
1044 }
1045
1046 pub fn last_rotation_at(&self) -> N {
1049 self.now -
1050 (self.now.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
1051 }
1052}
1053
1054#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1056#[cfg_attr(feature = "std", derive(PartialEq))]
1057pub struct OccupiedCore<H = Hash, N = BlockNumber> {
1058 pub next_up_on_available: Option<ScheduledCore>,
1062 pub occupied_since: N,
1064 pub time_out_at: N,
1066 pub next_up_on_time_out: Option<ScheduledCore>,
1070 pub availability: BitVec<u8, bitvec::order::Lsb0>,
1074 pub group_responsible: GroupIndex,
1076 pub candidate_hash: CandidateHash,
1078 pub candidate_descriptor: CandidateDescriptor<H>,
1080}
1081
1082impl<H, N> OccupiedCore<H, N> {
1083 pub fn para_id(&self) -> Id {
1085 self.candidate_descriptor.para_id
1086 }
1087}
1088
1089#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1091#[cfg_attr(feature = "std", derive(PartialEq))]
1092pub struct ScheduledCore {
1093 pub para_id: Id,
1095 pub collator: Option<CollatorId>,
1099}
1100
1101#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1103#[cfg_attr(feature = "std", derive(PartialEq))]
1104pub enum CoreState<H = Hash, N = BlockNumber> {
1105 #[codec(index = 0)]
1107 Occupied(OccupiedCore<H, N>),
1108 #[codec(index = 1)]
1114 Scheduled(ScheduledCore),
1115 #[codec(index = 2)]
1119 Free,
1120}
1121
1122impl<N> CoreState<N> {
1123 #[deprecated(
1128 note = "`para_id` will be removed. Use `ClaimQueue` to query the scheduled `para_id` instead."
1129 )]
1130 pub fn para_id(&self) -> Option<Id> {
1131 match self {
1132 Self::Occupied(ref core) => core.next_up_on_available.as_ref().map(|n| n.para_id),
1133 Self::Scheduled(core) => Some(core.para_id),
1134 Self::Free => None,
1135 }
1136 }
1137
1138 pub fn is_occupied(&self) -> bool {
1140 matches!(self, Self::Occupied(_))
1141 }
1142}
1143
1144#[derive(Clone, Copy, Encode, Decode, TypeInfo, RuntimeDebug)]
1146#[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash))]
1147pub enum OccupiedCoreAssumption {
1148 #[codec(index = 0)]
1150 Included,
1151 #[codec(index = 1)]
1153 TimedOut,
1154 #[codec(index = 2)]
1156 Free,
1157}
1158
1159#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1161#[cfg_attr(feature = "std", derive(PartialEq))]
1162pub enum CandidateEvent<H = Hash> {
1163 #[codec(index = 0)]
1166 CandidateBacked(CandidateReceipt<H>, HeadData, CoreIndex, GroupIndex),
1167 #[codec(index = 1)]
1171 CandidateIncluded(CandidateReceipt<H>, HeadData, CoreIndex, GroupIndex),
1172 #[codec(index = 2)]
1175 CandidateTimedOut(CandidateReceipt<H>, HeadData, CoreIndex),
1176}
1177
1178#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1180#[cfg_attr(feature = "std", derive(PartialEq))]
1181pub struct ScrapedOnChainVotes<H: Encode + Decode = Hash> {
1182 pub session: SessionIndex,
1184 pub backing_validators_per_candidate:
1187 Vec<(CandidateReceipt<H>, Vec<(ValidatorIndex, ValidityAttestation)>)>,
1188 pub disputes: MultiDisputeStatementSet,
1192}
1193
1194#[derive(Clone, RuntimeDebug)]
1196pub struct ApprovalVote(pub CandidateHash);
1197
1198impl ApprovalVote {
1199 pub fn signing_payload(&self, session_index: SessionIndex) -> Vec<u8> {
1201 const MAGIC: [u8; 4] = *b"APPR";
1202
1203 (MAGIC, &self.0, session_index).encode()
1204 }
1205}
1206
1207#[derive(Clone, RuntimeDebug)]
1209pub struct ApprovalVoteMultipleCandidates<'a>(pub &'a [CandidateHash]);
1210
1211impl<'a> ApprovalVoteMultipleCandidates<'a> {
1212 pub fn signing_payload(&self, session_index: SessionIndex) -> Vec<u8> {
1214 const MAGIC: [u8; 4] = *b"APPR";
1215 if self.0.len() == 1 {
1220 (MAGIC, self.0.first().expect("QED: we just checked"), session_index).encode()
1221 } else {
1222 (MAGIC, &self.0, session_index).encode()
1223 }
1224 }
1225}
1226
1227#[derive(
1229 RuntimeDebug,
1230 Copy,
1231 Clone,
1232 PartialEq,
1233 Encode,
1234 Decode,
1235 TypeInfo,
1236 serde::Serialize,
1237 serde::Deserialize,
1238)]
1239pub struct ApprovalVotingParams {
1240 pub max_approval_coalesce_count: u32,
1245}
1246
1247impl Default for ApprovalVotingParams {
1248 fn default() -> Self {
1249 Self { max_approval_coalesce_count: 1 }
1250 }
1251}
1252
1253#[repr(u8)]
1255pub enum ValidityError {
1256 InvalidEthereumSignature = 0,
1258 SignerHasNoClaim = 1,
1260 NoPermission = 2,
1262 InvalidStatement = 3,
1264}
1265
1266impl From<ValidityError> for u8 {
1267 fn from(err: ValidityError) -> Self {
1268 err as u8
1269 }
1270}
1271
1272#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1275#[cfg_attr(feature = "std", derive(PartialEq))]
1276pub struct AbridgedHostConfiguration {
1277 pub max_code_size: u32,
1279 pub max_head_data_size: u32,
1281 pub max_upward_queue_count: u32,
1283 pub max_upward_queue_size: u32,
1287 pub max_upward_message_size: u32,
1291 pub max_upward_message_num_per_candidate: u32,
1295 pub hrmp_max_message_num_per_candidate: u32,
1299 pub validation_upgrade_cooldown: BlockNumber,
1301 pub validation_upgrade_delay: BlockNumber,
1303 pub async_backing_params: AsyncBackingParams,
1305}
1306
1307#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1310#[cfg_attr(feature = "std", derive(PartialEq))]
1311pub struct AbridgedHrmpChannel {
1312 pub max_capacity: u32,
1314 pub max_total_size: u32,
1316 pub max_message_size: u32,
1318 pub msg_count: u32,
1321 pub total_size: u32,
1324 pub mqc_head: Option<Hash>,
1332}
1333
1334#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
1336pub enum UpgradeRestriction {
1337 #[codec(index = 0)]
1340 Present,
1341}
1342
1343#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
1349pub enum UpgradeGoAhead {
1350 #[codec(index = 0)]
1359 Abort,
1360 #[codec(index = 1)]
1364 GoAhead,
1365}
1366
1367pub const POLKADOT_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"POL1";
1369
1370#[derive(Decode, Encode, Clone, PartialEq, Eq)]
1372pub enum ConsensusLog {
1373 #[codec(index = 1)]
1375 ParaUpgradeCode(Id, ValidationCodeHash),
1376 #[codec(index = 2)]
1378 ParaScheduleUpgradeCode(Id, ValidationCodeHash, BlockNumber),
1379 #[codec(index = 3)]
1382 ForceApprove(BlockNumber),
1383 #[codec(index = 4)]
1392 Revert(BlockNumber),
1393}
1394
1395impl ConsensusLog {
1396 pub fn from_digest_item(
1398 digest_item: &sp_runtime::DigestItem,
1399 ) -> Result<Option<Self>, codec::Error> {
1400 match digest_item {
1401 sp_runtime::DigestItem::Consensus(id, encoded) if id == &POLKADOT_ENGINE_ID =>
1402 Ok(Some(Self::decode(&mut &encoded[..])?)),
1403 _ => Ok(None),
1404 }
1405 }
1406}
1407
1408impl From<ConsensusLog> for sp_runtime::DigestItem {
1409 fn from(c: ConsensusLog) -> sp_runtime::DigestItem {
1410 Self::Consensus(POLKADOT_ENGINE_ID, c.encode())
1411 }
1412}
1413
1414#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1418pub enum DisputeStatement {
1419 #[codec(index = 0)]
1421 Valid(ValidDisputeStatementKind),
1422 #[codec(index = 1)]
1424 Invalid(InvalidDisputeStatementKind),
1425}
1426
1427impl DisputeStatement {
1428 pub fn payload_data(
1433 &self,
1434 candidate_hash: CandidateHash,
1435 session: SessionIndex,
1436 ) -> Result<Vec<u8>, ()> {
1437 match self {
1438 DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) =>
1439 Ok(ExplicitDisputeStatement { valid: true, candidate_hash, session }
1440 .signing_payload()),
1441 DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded(
1442 inclusion_parent,
1443 )) => Ok(CompactStatement::Seconded(candidate_hash).signing_payload(&SigningContext {
1444 session_index: session,
1445 parent_hash: *inclusion_parent,
1446 })),
1447 DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent)) =>
1448 Ok(CompactStatement::Valid(candidate_hash).signing_payload(&SigningContext {
1449 session_index: session,
1450 parent_hash: *inclusion_parent,
1451 })),
1452 DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) =>
1453 Ok(ApprovalVote(candidate_hash).signing_payload(session)),
1454 DisputeStatement::Valid(
1455 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes),
1456 ) =>
1457 if candidate_hashes.contains(&candidate_hash) {
1458 Ok(ApprovalVoteMultipleCandidates(candidate_hashes).signing_payload(session))
1459 } else {
1460 Err(())
1461 },
1462 DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit) =>
1463 Ok(ExplicitDisputeStatement { valid: false, candidate_hash, session }
1464 .signing_payload()),
1465 }
1466 }
1467
1468 pub fn check_signature(
1470 &self,
1471 validator_public: &ValidatorId,
1472 candidate_hash: CandidateHash,
1473 session: SessionIndex,
1474 validator_signature: &ValidatorSignature,
1475 ) -> Result<(), ()> {
1476 let payload = self.payload_data(candidate_hash, session)?;
1477
1478 if validator_signature.verify(&payload[..], &validator_public) {
1479 Ok(())
1480 } else {
1481 Err(())
1482 }
1483 }
1484
1485 pub fn indicates_validity(&self) -> bool {
1487 match *self {
1488 DisputeStatement::Valid(_) => true,
1489 DisputeStatement::Invalid(_) => false,
1490 }
1491 }
1492
1493 pub fn indicates_invalidity(&self) -> bool {
1495 match *self {
1496 DisputeStatement::Valid(_) => false,
1497 DisputeStatement::Invalid(_) => true,
1498 }
1499 }
1500
1501 pub fn is_backing(&self) -> bool {
1503 match self {
1504 Self::Valid(s) => s.is_backing(),
1505 Self::Invalid(_) => false,
1506 }
1507 }
1508}
1509
1510#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1512pub enum ValidDisputeStatementKind {
1513 #[codec(index = 0)]
1515 Explicit,
1516 #[codec(index = 1)]
1518 BackingSeconded(Hash),
1519 #[codec(index = 2)]
1521 BackingValid(Hash),
1522 #[codec(index = 3)]
1524 ApprovalChecking,
1525 #[codec(index = 4)]
1530 ApprovalCheckingMultipleCandidates(Vec<CandidateHash>),
1531}
1532
1533impl ValidDisputeStatementKind {
1534 pub fn is_backing(&self) -> bool {
1536 match self {
1537 ValidDisputeStatementKind::BackingSeconded(_) |
1538 ValidDisputeStatementKind::BackingValid(_) => true,
1539 ValidDisputeStatementKind::Explicit |
1540 ValidDisputeStatementKind::ApprovalChecking |
1541 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(_) => false,
1542 }
1543 }
1544}
1545
1546#[derive(Encode, Decode, Copy, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1548pub enum InvalidDisputeStatementKind {
1549 #[codec(index = 0)]
1551 Explicit,
1552}
1553
1554#[derive(Clone, PartialEq, RuntimeDebug)]
1556pub struct ExplicitDisputeStatement {
1557 pub valid: bool,
1559 pub candidate_hash: CandidateHash,
1561 pub session: SessionIndex,
1563}
1564
1565impl ExplicitDisputeStatement {
1566 pub fn signing_payload(&self) -> Vec<u8> {
1568 const MAGIC: [u8; 4] = *b"DISP";
1569
1570 (MAGIC, self.valid, self.candidate_hash, self.session).encode()
1571 }
1572}
1573
1574#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1576pub struct DisputeStatementSet {
1577 pub candidate_hash: CandidateHash,
1579 pub session: SessionIndex,
1581 pub statements: Vec<(DisputeStatement, ValidatorIndex, ValidatorSignature)>,
1583}
1584
1585impl From<CheckedDisputeStatementSet> for DisputeStatementSet {
1586 fn from(other: CheckedDisputeStatementSet) -> Self {
1587 other.0
1588 }
1589}
1590
1591impl AsRef<DisputeStatementSet> for DisputeStatementSet {
1592 fn as_ref(&self) -> &DisputeStatementSet {
1593 &self
1594 }
1595}
1596
1597pub type MultiDisputeStatementSet = Vec<DisputeStatementSet>;
1599
1600#[derive(Clone, PartialEq, RuntimeDebug, Encode)]
1602pub struct CheckedDisputeStatementSet(DisputeStatementSet);
1603
1604impl AsRef<DisputeStatementSet> for CheckedDisputeStatementSet {
1605 fn as_ref(&self) -> &DisputeStatementSet {
1606 &self.0
1607 }
1608}
1609
1610impl core::cmp::PartialEq<DisputeStatementSet> for CheckedDisputeStatementSet {
1611 fn eq(&self, other: &DisputeStatementSet) -> bool {
1612 self.0.eq(other)
1613 }
1614}
1615
1616impl CheckedDisputeStatementSet {
1617 pub fn unchecked_from_unchecked(unchecked: DisputeStatementSet) -> Self {
1620 Self(unchecked)
1621 }
1622}
1623
1624pub type CheckedMultiDisputeStatementSet = Vec<CheckedDisputeStatementSet>;
1626
1627#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, TypeInfo)]
1629pub struct DisputeState<N = BlockNumber> {
1630 pub validators_for: BitVec<u8, bitvec::order::Lsb0>, pub validators_against: BitVec<u8, bitvec::order::Lsb0>, pub start: N,
1636 pub concluded_at: Option<N>,
1638}
1639
1640#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1642pub struct InherentData<HDR: HeaderT = Header> {
1643 pub bitfields: UncheckedSignedAvailabilityBitfields,
1645 pub backed_candidates: Vec<BackedCandidate<HDR::Hash>>,
1647 pub disputes: MultiDisputeStatementSet,
1649 pub parent_header: HDR,
1651}
1652
1653#[derive(Clone, Eq, PartialEq, Decode, Encode, RuntimeDebug, TypeInfo)]
1656pub enum ValidityAttestation {
1657 #[codec(index = 1)]
1660 Implicit(ValidatorSignature),
1661 #[codec(index = 2)]
1664 Explicit(ValidatorSignature),
1665}
1666
1667impl ValidityAttestation {
1668 pub fn to_compact_statement(&self, candidate_hash: CandidateHash) -> CompactStatement {
1671 match *self {
1675 ValidityAttestation::Implicit(_) => CompactStatement::Seconded(candidate_hash),
1676 ValidityAttestation::Explicit(_) => CompactStatement::Valid(candidate_hash),
1677 }
1678 }
1679
1680 pub fn signature(&self) -> &ValidatorSignature {
1682 match *self {
1683 ValidityAttestation::Implicit(ref sig) => sig,
1684 ValidityAttestation::Explicit(ref sig) => sig,
1685 }
1686 }
1687
1688 pub fn signed_payload<H: Encode>(
1691 &self,
1692 candidate_hash: CandidateHash,
1693 signing_context: &SigningContext<H>,
1694 ) -> Vec<u8> {
1695 match *self {
1696 ValidityAttestation::Implicit(_) =>
1697 (CompactStatement::Seconded(candidate_hash), signing_context).encode(),
1698 ValidityAttestation::Explicit(_) =>
1699 (CompactStatement::Valid(candidate_hash), signing_context).encode(),
1700 }
1701 }
1702}
1703
1704#[derive(Clone, Eq, PartialEq, Default, Decode, Encode, RuntimeDebug)]
1706pub struct SigningContext<H = Hash> {
1707 pub session_index: sp_staking::SessionIndex,
1709 pub parent_hash: H,
1711}
1712
1713const BACKING_STATEMENT_MAGIC: [u8; 4] = *b"BKNG";
1714
1715#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
1718#[cfg_attr(feature = "std", derive(Hash))]
1719pub enum CompactStatement {
1720 Seconded(CandidateHash),
1722 Valid(CandidateHash),
1724}
1725
1726impl CompactStatement {
1727 pub fn signing_payload(&self, context: &SigningContext) -> Vec<u8> {
1730 (self, context).encode()
1731 }
1732
1733 pub fn candidate_hash(&self) -> &CandidateHash {
1735 match *self {
1736 CompactStatement::Seconded(ref h) | CompactStatement::Valid(ref h) => h,
1737 }
1738 }
1739}
1740
1741#[derive(Encode, Decode, TypeInfo)]
1743enum CompactStatementInner {
1744 #[codec(index = 1)]
1745 Seconded(CandidateHash),
1746 #[codec(index = 2)]
1747 Valid(CandidateHash),
1748}
1749
1750impl From<CompactStatement> for CompactStatementInner {
1751 fn from(s: CompactStatement) -> Self {
1752 match s {
1753 CompactStatement::Seconded(h) => CompactStatementInner::Seconded(h),
1754 CompactStatement::Valid(h) => CompactStatementInner::Valid(h),
1755 }
1756 }
1757}
1758
1759impl codec::Encode for CompactStatement {
1760 fn size_hint(&self) -> usize {
1761 4 + 1 + 32
1763 }
1764
1765 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
1766 dest.write(&BACKING_STATEMENT_MAGIC);
1767 CompactStatementInner::from(self.clone()).encode_to(dest)
1768 }
1769}
1770
1771impl codec::Decode for CompactStatement {
1772 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
1773 let maybe_magic = <[u8; 4]>::decode(input)?;
1774 if maybe_magic != BACKING_STATEMENT_MAGIC {
1775 return Err(codec::Error::from("invalid magic string"))
1776 }
1777
1778 Ok(match CompactStatementInner::decode(input)? {
1779 CompactStatementInner::Seconded(h) => CompactStatement::Seconded(h),
1780 CompactStatementInner::Valid(h) => CompactStatement::Valid(h),
1781 })
1782 }
1783}
1784
1785#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1787#[cfg_attr(feature = "std", derive(PartialEq))]
1788pub struct IndexedVec<K, V>(Vec<V>, PhantomData<fn(K) -> K>);
1789
1790impl<K, V> Default for IndexedVec<K, V> {
1791 fn default() -> Self {
1792 Self(vec![], PhantomData)
1793 }
1794}
1795
1796impl<K, V> From<Vec<V>> for IndexedVec<K, V> {
1797 fn from(validators: Vec<V>) -> Self {
1798 Self(validators, PhantomData)
1799 }
1800}
1801
1802impl<K, V> FromIterator<V> for IndexedVec<K, V> {
1803 fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
1804 Self(Vec::from_iter(iter), PhantomData)
1805 }
1806}
1807
1808impl<K, V> IndexedVec<K, V>
1809where
1810 V: Clone,
1811{
1812 pub fn get(&self, index: K) -> Option<&V>
1814 where
1815 K: TypeIndex,
1816 {
1817 self.0.get(index.type_index())
1818 }
1819
1820 pub fn get_mut(&mut self, index: K) -> Option<&mut V>
1822 where
1823 K: TypeIndex,
1824 {
1825 self.0.get_mut(index.type_index())
1826 }
1827
1828 pub fn len(&self) -> usize {
1830 self.0.len()
1831 }
1832
1833 pub fn to_vec(&self) -> Vec<V> {
1835 self.0.clone()
1836 }
1837
1838 pub fn iter(&self) -> Iter<'_, V> {
1840 self.0.iter()
1841 }
1842
1843 pub fn iter_mut(&mut self) -> IterMut<'_, V> {
1845 self.0.iter_mut()
1846 }
1847
1848 pub fn into_iter(self) -> IntoIter<V> {
1850 self.0.into_iter()
1851 }
1852
1853 pub fn is_empty(&self) -> bool {
1855 self.0.is_empty()
1856 }
1857}
1858
1859pub const fn byzantine_threshold(n: usize) -> usize {
1863 n.saturating_sub(1) / 3
1864}
1865
1866pub const fn supermajority_threshold(n: usize) -> usize {
1869 n - byzantine_threshold(n)
1870}
1871
1872pub fn effective_minimum_backing_votes(
1874 group_len: usize,
1875 configured_minimum_backing_votes: u32,
1876) -> usize {
1877 core::cmp::min(group_len, configured_minimum_backing_votes as usize)
1878}
1879
1880#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1885#[cfg_attr(feature = "std", derive(PartialEq))]
1886pub struct SessionInfo {
1887 pub active_validator_indices: Vec<ValidatorIndex>,
1891 pub random_seed: [u8; 32],
1893 pub dispute_period: SessionIndex,
1895
1896 pub validators: IndexedVec<ValidatorIndex, ValidatorId>,
1905 pub discovery_keys: Vec<AuthorityDiscoveryId>,
1912 pub assignment_keys: Vec<AssignmentId>,
1923 pub validator_groups: IndexedVec<GroupIndex, Vec<ValidatorIndex>>,
1927 pub n_cores: u32,
1929 pub zeroth_delay_tranche_width: u32,
1931 pub relay_vrf_modulo_samples: u32,
1933 pub n_delay_tranches: u32,
1935 pub no_show_slots: u32,
1938 pub needed_approvals: u32,
1940}
1941
1942#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1945pub struct PvfCheckStatement {
1946 pub accept: bool,
1948 pub subject: ValidationCodeHash,
1950 pub session_index: SessionIndex,
1952 pub validator_index: ValidatorIndex,
1954}
1955
1956impl PvfCheckStatement {
1957 pub fn signing_payload(&self) -> Vec<u8> {
1962 const MAGIC: [u8; 4] = *b"VCPC"; (MAGIC, self.accept, self.subject, self.session_index, self.validator_index).encode()
1964 }
1965}
1966
1967pub struct WellKnownKey<T> {
1971 pub key: Vec<u8>,
1973 _p: core::marker::PhantomData<T>,
1974}
1975
1976impl<T> From<Vec<u8>> for WellKnownKey<T> {
1977 fn from(key: Vec<u8>) -> Self {
1978 Self { key, _p: Default::default() }
1979 }
1980}
1981
1982impl<T> AsRef<[u8]> for WellKnownKey<T> {
1983 fn as_ref(&self) -> &[u8] {
1984 self.key.as_ref()
1985 }
1986}
1987
1988impl<T: Decode> WellKnownKey<T> {
1989 pub fn get(&self) -> Option<T> {
1991 sp_io::storage::get(&self.key)
1992 .and_then(|raw| codec::DecodeAll::decode_all(&mut raw.as_ref()).ok())
1993 }
1994}
1995
1996impl<T: Encode> WellKnownKey<T> {
1997 pub fn set(&self, value: T) {
1999 sp_io::storage::set(&self.key, &value.encode());
2000 }
2001}
2002
2003#[derive(Encode, Decode, TypeInfo, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
2005pub enum PvfPrepKind {
2006 Precheck,
2008
2009 Prepare,
2011}
2012
2013#[derive(Encode, Decode, TypeInfo, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
2015pub enum PvfExecKind {
2016 Backing,
2018 Approval,
2020}
2021
2022pub type NodeFeatures = BitVec<u8, bitvec::order::Lsb0>;
2024
2025pub mod node_features {
2027 #[repr(u8)]
2030 #[derive(Clone, Copy)]
2031 pub enum FeatureIndex {
2032 EnableAssignmentsV2 = 0,
2035 ElasticScalingMVP = 1,
2039 AvailabilityChunkMapping = 2,
2045 CandidateReceiptV2 = 3,
2049 FirstUnassigned = 4,
2053 }
2054}
2055
2056#[derive(
2058 RuntimeDebug,
2059 Copy,
2060 Clone,
2061 PartialEq,
2062 Encode,
2063 Decode,
2064 TypeInfo,
2065 serde::Serialize,
2066 serde::Deserialize,
2067)]
2068pub struct SchedulerParams<BlockNumber> {
2069 pub group_rotation_frequency: BlockNumber,
2073 pub paras_availability_period: BlockNumber,
2088 pub max_validators_per_core: Option<u32>,
2092 pub lookahead: u32,
2094 pub num_cores: u32,
2096 pub max_availability_timeouts: u32,
2098 pub on_demand_queue_max_size: u32,
2100 pub on_demand_target_queue_utilization: Perbill,
2102 pub on_demand_fee_variability: Perbill,
2105 pub on_demand_base_fee: Balance,
2107 pub ttl: BlockNumber,
2111}
2112
2113impl<BlockNumber: Default + From<u32>> Default for SchedulerParams<BlockNumber> {
2114 fn default() -> Self {
2115 Self {
2116 group_rotation_frequency: 1u32.into(),
2117 paras_availability_period: 1u32.into(),
2118 max_validators_per_core: Default::default(),
2119 lookahead: 1,
2120 num_cores: Default::default(),
2121 max_availability_timeouts: Default::default(),
2122 on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE,
2123 on_demand_target_queue_utilization: Perbill::from_percent(25),
2124 on_demand_fee_variability: Perbill::from_percent(3),
2125 on_demand_base_fee: 10_000_000u128,
2126 ttl: 5u32.into(),
2127 }
2128 }
2129}
2130
2131#[cfg(test)]
2132pub mod tests {
2133 use super::*;
2134 use bitvec::bitvec;
2135 use sp_core::sr25519;
2136
2137 pub fn dummy_committed_candidate_receipt() -> CommittedCandidateReceipt {
2138 let zeros = Hash::zero();
2139
2140 CommittedCandidateReceipt {
2141 descriptor: CandidateDescriptor {
2142 para_id: 0.into(),
2143 relay_parent: zeros,
2144 collator: CollatorId::from(sr25519::Public::default()),
2145 persisted_validation_data_hash: zeros,
2146 pov_hash: zeros,
2147 erasure_root: zeros,
2148 signature: CollatorSignature::from(sr25519::Signature::default()),
2149 para_head: zeros,
2150 validation_code_hash: ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).hash(),
2151 },
2152 commitments: CandidateCommitments {
2153 head_data: HeadData(vec![]),
2154 upward_messages: vec![].try_into().expect("empty vec fits within bounds"),
2155 new_validation_code: None,
2156 horizontal_messages: vec![].try_into().expect("empty vec fits within bounds"),
2157 processed_downward_messages: 0,
2158 hrmp_watermark: 0_u32,
2159 },
2160 }
2161 }
2162
2163 #[test]
2164 fn group_rotation_info_calculations() {
2165 let info =
2166 GroupRotationInfo { session_start_block: 10u32, now: 15, group_rotation_frequency: 5 };
2167
2168 assert_eq!(info.next_rotation_at(), 20);
2169 assert_eq!(info.last_rotation_at(), 15);
2170 }
2171
2172 #[test]
2173 fn group_for_core_is_core_for_group() {
2174 for cores in 1..=256 {
2175 for rotations in 0..(cores * 2) {
2176 let info = GroupRotationInfo {
2177 session_start_block: 0u32,
2178 now: rotations,
2179 group_rotation_frequency: 1,
2180 };
2181
2182 for core in 0..cores {
2183 let group = info.group_for_core(CoreIndex(core), cores as usize);
2184 assert_eq!(info.core_for_group(group, cores as usize).0, core);
2185 }
2186 }
2187 }
2188 }
2189
2190 #[test]
2191 fn collator_signature_payload_is_valid() {
2192 let h = Hash::default();
2194 assert_eq!(h.as_ref().len(), 32);
2195
2196 let _payload = collator_signature_payload(
2197 &Hash::repeat_byte(1),
2198 &5u32.into(),
2199 &Hash::repeat_byte(2),
2200 &Hash::repeat_byte(3),
2201 &Hash::repeat_byte(4).into(),
2202 );
2203 }
2204
2205 #[test]
2206 fn test_byzantine_threshold() {
2207 assert_eq!(byzantine_threshold(0), 0);
2208 assert_eq!(byzantine_threshold(1), 0);
2209 assert_eq!(byzantine_threshold(2), 0);
2210 assert_eq!(byzantine_threshold(3), 0);
2211 assert_eq!(byzantine_threshold(4), 1);
2212 assert_eq!(byzantine_threshold(5), 1);
2213 assert_eq!(byzantine_threshold(6), 1);
2214 assert_eq!(byzantine_threshold(7), 2);
2215 }
2216
2217 #[test]
2218 fn test_supermajority_threshold() {
2219 assert_eq!(supermajority_threshold(0), 0);
2220 assert_eq!(supermajority_threshold(1), 1);
2221 assert_eq!(supermajority_threshold(2), 2);
2222 assert_eq!(supermajority_threshold(3), 3);
2223 assert_eq!(supermajority_threshold(4), 3);
2224 assert_eq!(supermajority_threshold(5), 4);
2225 assert_eq!(supermajority_threshold(6), 5);
2226 assert_eq!(supermajority_threshold(7), 5);
2227 }
2228
2229 #[test]
2230 fn balance_bigger_than_usize() {
2231 let zero_b: Balance = 0;
2232 let zero_u: usize = 0;
2233
2234 assert!(zero_b.leading_zeros() >= zero_u.leading_zeros());
2235 }
2236
2237 #[test]
2238 fn test_backed_candidate_injected_core_index() {
2239 let initial_validator_indices = bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1];
2240 let mut candidate = BackedCandidate::new(
2241 dummy_committed_candidate_receipt(),
2242 vec![],
2243 initial_validator_indices.clone(),
2244 None,
2245 );
2246
2247 let (validator_indices, core_index) = candidate.validator_indices_and_core_index(false);
2249 assert_eq!(validator_indices, initial_validator_indices.as_bitslice());
2250 assert!(core_index.is_none());
2251
2252 let (validator_indices, core_index) = candidate.validator_indices_and_core_index(true);
2256 assert_eq!(validator_indices, initial_validator_indices.as_bitslice());
2257 assert!(core_index.is_none());
2258
2259 let encoded_validator_indices = candidate.validator_indices.clone();
2260 candidate.set_validator_indices_and_core_index(validator_indices.into(), core_index);
2261 assert_eq!(candidate.validator_indices, encoded_validator_indices);
2262
2263 let candidate = BackedCandidate::new(
2266 dummy_committed_candidate_receipt(),
2267 vec![],
2268 bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1, 0, 1, 0, 1, 0],
2269 None,
2270 );
2271 let (validator_indices, core_index) = candidate.validator_indices_and_core_index(true);
2272 assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0].as_bitslice());
2273 assert!(core_index.is_some());
2274
2275 let candidate = BackedCandidate::new(
2278 dummy_committed_candidate_receipt(),
2279 vec![],
2280 bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1],
2281 Some(CoreIndex(10)),
2282 );
2283 let (validator_indices, core_index) = candidate.validator_indices_and_core_index(false);
2284 assert_eq!(
2285 validator_indices,
2286 bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0]
2287 );
2288 assert!(core_index.is_none());
2289
2290 let mut candidate = BackedCandidate::new(
2292 dummy_committed_candidate_receipt(),
2293 vec![],
2294 bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1],
2295 Some(CoreIndex(10)),
2296 );
2297 let (validator_indices, core_index) = candidate.validator_indices_and_core_index(true);
2298 assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1]);
2299 assert_eq!(core_index, Some(CoreIndex(10)));
2300
2301 let encoded_validator_indices = candidate.validator_indices.clone();
2302 candidate.set_validator_indices_and_core_index(validator_indices.into(), core_index);
2303 assert_eq!(candidate.validator_indices, encoded_validator_indices);
2304 }
2305}