1use alloc::{
19 vec,
20 vec::{IntoIter, Vec},
21};
22use bitvec::{field::BitField, slice::BitSlice, vec::BitVec};
23use codec::{Decode, DecodeWithMemTracking, 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(
121 Eq,
122 Ord,
123 PartialEq,
124 PartialOrd,
125 Copy,
126 Clone,
127 Encode,
128 Decode,
129 DecodeWithMemTracking,
130 TypeInfo,
131 RuntimeDebug,
132)]
133#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))]
134pub struct ValidatorIndex(pub u32);
135
136#[derive(Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
143#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))]
144pub struct ChunkIndex(pub u32);
145
146impl From<ChunkIndex> for ValidatorIndex {
147 fn from(c_index: ChunkIndex) -> Self {
148 ValidatorIndex(c_index.0)
149 }
150}
151
152impl From<ValidatorIndex> for ChunkIndex {
153 fn from(v_index: ValidatorIndex) -> Self {
154 ChunkIndex(v_index.0)
155 }
156}
157
158impl From<u32> for ChunkIndex {
159 fn from(n: u32) -> Self {
160 ChunkIndex(n)
161 }
162}
163
164impl From<u32> for ValidatorIndex {
166 fn from(n: u32) -> Self {
167 ValidatorIndex(n)
168 }
169}
170
171impl TypeIndex for ValidatorIndex {
172 fn type_index(&self) -> usize {
173 self.0 as usize
174 }
175}
176
177sp_application_crypto::with_pair! {
178 pub type ValidatorPair = validator_app::Pair;
180}
181
182pub type ValidatorSignature = validator_app::Signature;
187
188pub mod well_known_keys {
190 use super::{HrmpChannelId, Id, WellKnownKey};
191 use alloc::vec::Vec;
192 use codec::Encode as _;
193 use hex_literal::hex;
194 use sp_io::hashing::twox_64;
195
196 pub const EPOCH_INDEX: &[u8] =
212 &hex!["1cb6f36e027abb2091cfb5110ab5087f38316cbf8fa0da822a20ac1c55bf1be3"];
213
214 pub const CURRENT_BLOCK_RANDOMNESS: &[u8] =
218 &hex!["1cb6f36e027abb2091cfb5110ab5087fd077dfdb8adb10f78f10a5df8742c545"];
219
220 pub const ONE_EPOCH_AGO_RANDOMNESS: &[u8] =
224 &hex!["1cb6f36e027abb2091cfb5110ab5087f7ce678799d3eff024253b90e84927cc6"];
225
226 pub const TWO_EPOCHS_AGO_RANDOMNESS: &[u8] =
230 &hex!["1cb6f36e027abb2091cfb5110ab5087f7a414cb008e0e61e46722aa60abdd672"];
231
232 pub const CURRENT_SLOT: &[u8] =
236 &hex!["1cb6f36e027abb2091cfb5110ab5087f06155b3cd9a8c9e5e9a23fd5dc13a5ed"];
237
238 pub const ACTIVE_CONFIG: &[u8] =
242 &hex!["06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"];
243
244 pub fn para_head(para_id: Id) -> Vec<u8> {
248 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c3"];
249
250 para_id.using_encoded(|para_id: &[u8]| {
251 prefix
252 .as_ref()
253 .iter()
254 .chain(twox_64(para_id).iter())
255 .chain(para_id.iter())
256 .cloned()
257 .collect()
258 })
259 }
260
261 #[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
268 pub fn relay_dispatch_queue_size(para_id: Id) -> Vec<u8> {
269 let prefix = hex!["f5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e"];
270
271 para_id.using_encoded(|para_id: &[u8]| {
272 prefix
273 .as_ref()
274 .iter()
275 .chain(twox_64(para_id).iter())
276 .chain(para_id.iter())
277 .cloned()
278 .collect()
279 })
280 }
281
282 #[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
284 pub fn relay_dispatch_queue_size_typed(para: Id) -> WellKnownKey<(u32, u32)> {
285 #[allow(deprecated)]
286 relay_dispatch_queue_size(para).into()
287 }
288
289 pub fn relay_dispatch_queue_remaining_capacity(para_id: Id) -> WellKnownKey<(u32, u32)> {
297 (b":relay_dispatch_queue_remaining_capacity", para_id).encode().into()
298 }
299
300 pub fn hrmp_channels(channel: HrmpChannelId) -> Vec<u8> {
304 let prefix = hex!["6a0da05ca59913bc38a8630590f2627cb6604cff828a6e3f579ca6c59ace013d"];
305
306 channel.using_encoded(|channel: &[u8]| {
307 prefix
308 .as_ref()
309 .iter()
310 .chain(twox_64(channel).iter())
311 .chain(channel.iter())
312 .cloned()
313 .collect()
314 })
315 }
316
317 pub fn hrmp_ingress_channel_index(para_id: Id) -> Vec<u8> {
321 let prefix = hex!["6a0da05ca59913bc38a8630590f2627c1d3719f5b0b12c7105c073c507445948"];
322
323 para_id.using_encoded(|para_id: &[u8]| {
324 prefix
325 .as_ref()
326 .iter()
327 .chain(twox_64(para_id).iter())
328 .chain(para_id.iter())
329 .cloned()
330 .collect()
331 })
332 }
333
334 pub fn hrmp_egress_channel_index(para_id: Id) -> Vec<u8> {
338 let prefix = hex!["6a0da05ca59913bc38a8630590f2627cf12b746dcf32e843354583c9702cc020"];
339
340 para_id.using_encoded(|para_id: &[u8]| {
341 prefix
342 .as_ref()
343 .iter()
344 .chain(twox_64(para_id).iter())
345 .chain(para_id.iter())
346 .cloned()
347 .collect()
348 })
349 }
350
351 pub fn dmq_mqc_head(para_id: Id) -> Vec<u8> {
356 let prefix = hex!["63f78c98723ddc9073523ef3beefda0c4d7fefc408aac59dbfe80a72ac8e3ce5"];
357
358 para_id.using_encoded(|para_id: &[u8]| {
359 prefix
360 .as_ref()
361 .iter()
362 .chain(twox_64(para_id).iter())
363 .chain(para_id.iter())
364 .cloned()
365 .collect()
366 })
367 }
368
369 pub fn upgrade_go_ahead_signal(para_id: Id) -> Vec<u8> {
374 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1949e94c040f5e73d9b7addd6cb603d15d3"];
375
376 para_id.using_encoded(|para_id: &[u8]| {
377 prefix
378 .as_ref()
379 .iter()
380 .chain(twox_64(para_id).iter())
381 .chain(para_id.iter())
382 .cloned()
383 .collect()
384 })
385 }
386
387 pub fn upgrade_restriction_signal(para_id: Id) -> Vec<u8> {
392 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa194f27bbb460270642b5bcaf032ea04d56a"];
393
394 para_id.using_encoded(|para_id: &[u8]| {
395 prefix
396 .as_ref()
397 .iter()
398 .chain(twox_64(para_id).iter())
399 .chain(para_id.iter())
400 .cloned()
401 .collect()
402 })
403 }
404}
405
406pub const PARACHAINS_INHERENT_IDENTIFIER: InherentIdentifier = *b"parachn0";
408
409pub const ASSIGNMENT_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"asgn");
411
412pub const MIN_CODE_SIZE: u32 = 9;
414
415pub const MAX_CODE_SIZE: u32 = 3 * 1024 * 1024;
425
426pub const MAX_HEAD_DATA_SIZE: u32 = 1 * 1024 * 1024;
433
434pub const MAX_POV_SIZE: u32 = 5 * 1024 * 1024;
442
443pub const ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE: u32 = 10_000;
447
448pub const ON_DEMAND_MAX_QUEUE_MAX_SIZE: u32 = 1_000_000_000;
454
455pub const LEGACY_MIN_BACKING_VOTES: u32 = 2;
458
459pub const DEFAULT_SCHEDULING_LOOKAHEAD: u32 = 3;
461
462mod assignment_app {
465 use sp_application_crypto::{app_crypto, sr25519};
466 app_crypto!(sr25519, super::ASSIGNMENT_KEY_TYPE_ID);
467}
468
469pub type AssignmentId = assignment_app::Public;
472
473sp_application_crypto::with_pair! {
474 pub type AssignmentPair = assignment_app::Pair;
477}
478
479pub type CandidateIndex = u32;
481
482pub fn collator_signature_payload<H: AsRef<[u8]>>(
484 relay_parent: &H,
485 para_id: &Id,
486 persisted_validation_data_hash: &Hash,
487 pov_hash: &Hash,
488 validation_code_hash: &ValidationCodeHash,
489) -> [u8; 132] {
490 let mut payload = [0u8; 132];
492
493 payload[0..32].copy_from_slice(relay_parent.as_ref());
494 u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s));
495 payload[36..68].copy_from_slice(persisted_validation_data_hash.as_ref());
496 payload[68..100].copy_from_slice(pov_hash.as_ref());
497 payload[100..132].copy_from_slice(validation_code_hash.as_ref());
498
499 payload
500}
501
502pub(crate) fn check_collator_signature<H: AsRef<[u8]>>(
503 relay_parent: &H,
504 para_id: &Id,
505 persisted_validation_data_hash: &Hash,
506 pov_hash: &Hash,
507 validation_code_hash: &ValidationCodeHash,
508 collator: &CollatorId,
509 signature: &CollatorSignature,
510) -> Result<(), ()> {
511 let payload = collator_signature_payload(
512 relay_parent,
513 para_id,
514 persisted_validation_data_hash,
515 pov_hash,
516 validation_code_hash,
517 );
518
519 if signature.verify(&payload[..], collator) {
520 Ok(())
521 } else {
522 Err(())
523 }
524}
525
526#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
528#[cfg_attr(feature = "std", derive(Hash))]
529pub struct CandidateDescriptor<H = Hash> {
530 pub para_id: Id,
532 pub relay_parent: H,
534 pub collator: CollatorId,
536 pub persisted_validation_data_hash: Hash,
540 pub pov_hash: Hash,
542 pub erasure_root: Hash,
544 pub signature: CollatorSignature,
547 pub para_head: Hash,
549 pub validation_code_hash: ValidationCodeHash,
551}
552
553impl<H: AsRef<[u8]>> CandidateDescriptor<H> {
554 pub fn check_collator_signature(&self) -> Result<(), ()> {
556 check_collator_signature(
557 &self.relay_parent,
558 &self.para_id,
559 &self.persisted_validation_data_hash,
560 &self.pov_hash,
561 &self.validation_code_hash,
562 &self.collator,
563 &self.signature,
564 )
565 }
566}
567
568#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
570pub struct CandidateReceipt<H = Hash> {
571 pub descriptor: CandidateDescriptor<H>,
573 pub commitments_hash: Hash,
575}
576
577impl<H> CandidateReceipt<H> {
578 pub fn descriptor(&self) -> &CandidateDescriptor<H> {
580 &self.descriptor
581 }
582
583 pub fn hash(&self) -> CandidateHash
585 where
586 H: Encode,
587 {
588 CandidateHash(BlakeTwo256::hash_of(self))
589 }
590}
591
592#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
594#[cfg_attr(feature = "std", derive(Hash))]
595pub struct CommittedCandidateReceipt<H = Hash> {
596 pub descriptor: CandidateDescriptor<H>,
598 pub commitments: CandidateCommitments,
600}
601
602impl<H> CommittedCandidateReceipt<H> {
603 pub fn descriptor(&self) -> &CandidateDescriptor<H> {
605 &self.descriptor
606 }
607}
608
609impl<H: Clone> CommittedCandidateReceipt<H> {
610 pub fn to_plain(&self) -> CandidateReceipt<H> {
612 CandidateReceipt {
613 descriptor: self.descriptor.clone(),
614 commitments_hash: self.commitments.hash(),
615 }
616 }
617
618 pub fn hash(&self) -> CandidateHash
623 where
624 H: Encode,
625 {
626 self.to_plain().hash()
627 }
628
629 pub fn corresponds_to(&self, receipt: &CandidateReceipt<H>) -> bool
631 where
632 H: PartialEq,
633 {
634 receipt.descriptor == self.descriptor && receipt.commitments_hash == self.commitments.hash()
635 }
636}
637
638impl PartialOrd for CommittedCandidateReceipt {
639 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
640 Some(self.cmp(other))
641 }
642}
643
644impl Ord for CommittedCandidateReceipt {
645 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
646 self.descriptor()
649 .para_id
650 .cmp(&other.descriptor().para_id)
651 .then_with(|| self.commitments.head_data.cmp(&other.commitments.head_data))
652 }
653}
654
655#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
677#[cfg_attr(feature = "std", derive(Default))]
678pub struct PersistedValidationData<H = Hash, N = BlockNumber> {
679 pub parent_head: HeadData,
681 pub relay_parent_number: N,
683 pub relay_parent_storage_root: H,
685 pub max_pov_size: u32,
687}
688
689impl<H: Encode, N: Encode> PersistedValidationData<H, N> {
690 pub fn hash(&self) -> Hash {
692 BlakeTwo256::hash_of(self)
693 }
694}
695
696#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
698#[cfg_attr(feature = "std", derive(Default, Hash))]
699pub struct CandidateCommitments<N = BlockNumber> {
700 pub upward_messages: UpwardMessages,
702 pub horizontal_messages: HorizontalMessages,
704 pub new_validation_code: Option<ValidationCode>,
706 pub head_data: HeadData,
708 pub processed_downward_messages: u32,
710 pub hrmp_watermark: N,
713}
714
715impl CandidateCommitments {
716 pub fn hash(&self) -> Hash {
718 BlakeTwo256::hash_of(self)
719 }
720}
721
722#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, RuntimeDebug, TypeInfo)]
726pub struct AvailabilityBitfield(pub BitVec<u8, bitvec::order::Lsb0>);
727
728impl From<BitVec<u8, bitvec::order::Lsb0>> for AvailabilityBitfield {
729 fn from(inner: BitVec<u8, bitvec::order::Lsb0>) -> Self {
730 AvailabilityBitfield(inner)
731 }
732}
733
734pub type SignedStatement = Signed<CompactStatement>;
736pub type UncheckedSignedStatement = UncheckedSigned<CompactStatement>;
738
739pub type SignedAvailabilityBitfield = Signed<AvailabilityBitfield>;
741pub type UncheckedSignedAvailabilityBitfield = UncheckedSigned<AvailabilityBitfield>;
743
744pub type SignedAvailabilityBitfields = Vec<SignedAvailabilityBitfield>;
746pub type UncheckedSignedAvailabilityBitfields = Vec<UncheckedSignedAvailabilityBitfield>;
749
750#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
752pub struct BackedCandidate<H = Hash> {
753 candidate: CommittedCandidateReceipt<H>,
755 validity_votes: Vec<ValidityAttestation>,
757 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
760}
761
762impl<H> BackedCandidate<H> {
763 pub fn new(
765 candidate: CommittedCandidateReceipt<H>,
766 validity_votes: Vec<ValidityAttestation>,
767 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
768 core_index: CoreIndex,
769 ) -> Self {
770 let mut instance = Self { candidate, validity_votes, validator_indices };
771 instance.inject_core_index(core_index);
772 instance
773 }
774
775 pub fn descriptor(&self) -> &CandidateDescriptor<H> {
777 &self.candidate.descriptor
778 }
779
780 pub fn candidate(&self) -> &CommittedCandidateReceipt<H> {
782 &self.candidate
783 }
784
785 pub fn validity_votes(&self) -> &[ValidityAttestation] {
787 &self.validity_votes
788 }
789
790 pub fn validity_votes_mut(&mut self) -> &mut Vec<ValidityAttestation> {
792 &mut self.validity_votes
793 }
794
795 pub fn hash(&self) -> CandidateHash
797 where
798 H: Clone + Encode,
799 {
800 self.candidate.hash()
801 }
802
803 pub fn receipt(&self) -> CandidateReceipt<H>
805 where
806 H: Clone,
807 {
808 self.candidate.to_plain()
809 }
810
811 pub fn validator_indices_and_core_index(
813 &self,
814 ) -> (&BitSlice<u8, bitvec::order::Lsb0>, Option<CoreIndex>) {
815 let core_idx_offset = self.validator_indices.len().saturating_sub(8);
817 if core_idx_offset > 0 {
818 let (validator_indices_slice, core_idx_slice) =
819 self.validator_indices.split_at(core_idx_offset);
820 return (validator_indices_slice, Some(CoreIndex(core_idx_slice.load::<u8>() as u32)));
821 }
822
823 (&self.validator_indices, None)
824 }
825
826 fn inject_core_index(&mut self, core_index: CoreIndex) {
828 let core_index_to_inject: BitVec<u8, bitvec::order::Lsb0> =
829 BitVec::from_vec(vec![core_index.0 as u8]);
830 self.validator_indices.extend(core_index_to_inject);
831 }
832
833 pub fn set_validator_indices_and_core_index(
835 &mut self,
836 new_indices: BitVec<u8, bitvec::order::Lsb0>,
837 maybe_core_index: Option<CoreIndex>,
838 ) {
839 self.validator_indices = new_indices;
840
841 if let Some(core_index) = maybe_core_index {
842 self.inject_core_index(core_index);
843 }
844 }
845}
846
847pub fn check_candidate_backing<H: AsRef<[u8]> + Clone + Encode + core::fmt::Debug>(
858 candidate_hash: CandidateHash,
859 validity_votes: &[ValidityAttestation],
860 validator_indices: &BitSlice<u8, bitvec::order::Lsb0>,
861 signing_context: &SigningContext<H>,
862 group_len: usize,
863 validator_lookup: impl Fn(usize) -> Option<ValidatorId>,
864) -> Result<usize, ()> {
865 if validator_indices.len() != group_len {
866 log::debug!(
867 target: LOG_TARGET,
868 "Check candidate backing: indices mismatch: group_len = {} , indices_len = {}",
869 group_len,
870 validator_indices.len(),
871 );
872 return Err(())
873 }
874
875 if validity_votes.len() > group_len {
876 log::debug!(
877 target: LOG_TARGET,
878 "Check candidate backing: Too many votes, expected: {}, found: {}",
879 group_len,
880 validity_votes.len(),
881 );
882 return Err(())
883 }
884
885 let mut signed = 0;
886 for ((val_in_group_idx, _), attestation) in validator_indices
887 .iter()
888 .enumerate()
889 .filter(|(_, signed)| **signed)
890 .zip(validity_votes.iter())
891 {
892 let validator_id = validator_lookup(val_in_group_idx).ok_or(())?;
893 let payload = attestation.signed_payload(candidate_hash, signing_context);
894 let sig = attestation.signature();
895
896 if sig.verify(&payload[..], &validator_id) {
897 signed += 1;
898 } else {
899 log::debug!(
900 target: LOG_TARGET,
901 "Check candidate backing: Invalid signature. validator_id = {:?}, validator_index = {} ",
902 validator_id,
903 val_in_group_idx,
904 );
905 return Err(())
906 }
907 }
908
909 if signed != validity_votes.len() {
910 log::error!(
911 target: LOG_TARGET,
912 "Check candidate backing: Too many signatures, expected = {}, found = {}",
913 validity_votes.len(),
914 signed,
915 );
916 return Err(())
917 }
918
919 Ok(signed)
920}
921
922#[derive(
924 Encode,
925 Decode,
926 DecodeWithMemTracking,
927 Default,
928 PartialOrd,
929 Ord,
930 Eq,
931 PartialEq,
932 Clone,
933 Copy,
934 TypeInfo,
935 RuntimeDebug,
936)]
937#[cfg_attr(feature = "std", derive(Hash))]
938pub struct CoreIndex(pub u32);
939
940impl From<u32> for CoreIndex {
941 fn from(i: u32) -> CoreIndex {
942 CoreIndex(i)
943 }
944}
945
946impl TypeIndex for CoreIndex {
947 fn type_index(&self) -> usize {
948 self.0 as usize
949 }
950}
951
952#[derive(
954 Encode,
955 Decode,
956 DecodeWithMemTracking,
957 Default,
958 Clone,
959 Copy,
960 Debug,
961 PartialEq,
962 Eq,
963 TypeInfo,
964 PartialOrd,
965 Ord,
966)]
967#[cfg_attr(feature = "std", derive(Hash))]
968pub struct GroupIndex(pub u32);
969
970impl From<u32> for GroupIndex {
971 fn from(i: u32) -> GroupIndex {
972 GroupIndex(i)
973 }
974}
975
976impl TypeIndex for GroupIndex {
977 fn type_index(&self) -> usize {
978 self.0 as usize
979 }
980}
981
982#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
984pub struct ParathreadClaim(pub Id, pub Option<CollatorId>);
985
986#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
988pub struct ParathreadEntry {
989 pub claim: ParathreadClaim,
991 pub retries: u32,
993}
994
995#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
997#[cfg_attr(feature = "std", derive(PartialEq))]
998pub struct GroupRotationInfo<N = BlockNumber> {
999 pub session_start_block: N,
1001 pub group_rotation_frequency: N,
1003 pub now: N,
1005}
1006
1007impl GroupRotationInfo {
1008 pub fn group_for_core(&self, core_index: CoreIndex, cores: usize) -> GroupIndex {
1013 if self.group_rotation_frequency == 0 {
1014 return GroupIndex(core_index.0)
1015 }
1016 if cores == 0 {
1017 return GroupIndex(0)
1018 }
1019
1020 let cores = core::cmp::min(cores, u32::MAX as usize);
1021 let blocks_since_start = self.now.saturating_sub(self.session_start_block);
1022 let rotations = blocks_since_start / self.group_rotation_frequency;
1023
1024 let idx = (core_index.0 as usize + rotations as usize) % cores;
1027 GroupIndex(idx as u32)
1028 }
1029
1030 pub fn core_for_group(&self, group_index: GroupIndex, cores: usize) -> CoreIndex {
1035 if self.group_rotation_frequency == 0 {
1036 return CoreIndex(group_index.0)
1037 }
1038 if cores == 0 {
1039 return CoreIndex(0)
1040 }
1041
1042 let cores = core::cmp::min(cores, u32::MAX as usize);
1043 let blocks_since_start = self.now.saturating_sub(self.session_start_block);
1044 let rotations = blocks_since_start / self.group_rotation_frequency;
1045 let rotations = rotations % cores as u32;
1046
1047 let idx = (group_index.0 as usize + cores - rotations as usize) % cores;
1053 CoreIndex(idx as u32)
1054 }
1055
1056 pub fn bump_rotation(&self) -> Self {
1058 GroupRotationInfo {
1059 session_start_block: self.session_start_block,
1060 group_rotation_frequency: self.group_rotation_frequency,
1061 now: self.next_rotation_at(),
1062 }
1063 }
1064}
1065
1066impl<N: Saturating + BaseArithmetic + Copy> GroupRotationInfo<N> {
1067 pub fn next_rotation_at(&self) -> N {
1070 let cycle_once = self.now + self.group_rotation_frequency;
1071 cycle_once -
1072 (cycle_once.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
1073 }
1074
1075 pub fn last_rotation_at(&self) -> N {
1078 self.now -
1079 (self.now.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
1080 }
1081}
1082
1083#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1085#[cfg_attr(feature = "std", derive(PartialEq))]
1086pub struct OccupiedCore<H = Hash, N = BlockNumber> {
1087 pub next_up_on_available: Option<ScheduledCore>,
1091 pub occupied_since: N,
1093 pub time_out_at: N,
1095 pub next_up_on_time_out: Option<ScheduledCore>,
1099 pub availability: BitVec<u8, bitvec::order::Lsb0>,
1103 pub group_responsible: GroupIndex,
1105 pub candidate_hash: CandidateHash,
1107 pub candidate_descriptor: CandidateDescriptor<H>,
1109}
1110
1111impl<H, N> OccupiedCore<H, N> {
1112 pub fn para_id(&self) -> Id {
1114 self.candidate_descriptor.para_id
1115 }
1116}
1117
1118#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1120#[cfg_attr(feature = "std", derive(PartialEq))]
1121pub struct ScheduledCore {
1122 pub para_id: Id,
1124 pub collator: Option<CollatorId>,
1128}
1129
1130#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1132#[cfg_attr(feature = "std", derive(PartialEq))]
1133pub enum CoreState<H = Hash, N = BlockNumber> {
1134 #[codec(index = 0)]
1136 Occupied(OccupiedCore<H, N>),
1137 #[codec(index = 1)]
1143 Scheduled(ScheduledCore),
1144 #[codec(index = 2)]
1148 Free,
1149}
1150
1151impl<N> CoreState<N> {
1152 #[deprecated(
1157 note = "`para_id` will be removed. Use `ClaimQueue` to query the scheduled `para_id` instead."
1158 )]
1159 pub fn para_id(&self) -> Option<Id> {
1160 match self {
1161 Self::Occupied(ref core) => core.next_up_on_available.as_ref().map(|n| n.para_id),
1162 Self::Scheduled(core) => Some(core.para_id),
1163 Self::Free => None,
1164 }
1165 }
1166
1167 pub fn is_occupied(&self) -> bool {
1169 matches!(self, Self::Occupied(_))
1170 }
1171}
1172
1173#[derive(Clone, Copy, Encode, Decode, TypeInfo, RuntimeDebug)]
1175#[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash))]
1176pub enum OccupiedCoreAssumption {
1177 #[codec(index = 0)]
1179 Included,
1180 #[codec(index = 1)]
1182 TimedOut,
1183 #[codec(index = 2)]
1185 Free,
1186}
1187
1188#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1190#[cfg_attr(feature = "std", derive(PartialEq))]
1191pub enum CandidateEvent<H = Hash> {
1192 #[codec(index = 0)]
1195 CandidateBacked(CandidateReceipt<H>, HeadData, CoreIndex, GroupIndex),
1196 #[codec(index = 1)]
1200 CandidateIncluded(CandidateReceipt<H>, HeadData, CoreIndex, GroupIndex),
1201 #[codec(index = 2)]
1204 CandidateTimedOut(CandidateReceipt<H>, HeadData, CoreIndex),
1205}
1206
1207#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1209#[cfg_attr(feature = "std", derive(PartialEq))]
1210pub struct ScrapedOnChainVotes<H: Encode + Decode = Hash> {
1211 pub session: SessionIndex,
1213 pub backing_validators_per_candidate:
1216 Vec<(CandidateReceipt<H>, Vec<(ValidatorIndex, ValidityAttestation)>)>,
1217 pub disputes: MultiDisputeStatementSet,
1221}
1222
1223#[derive(Clone, RuntimeDebug)]
1225pub struct ApprovalVote(pub CandidateHash);
1226
1227impl ApprovalVote {
1228 pub fn signing_payload(&self, session_index: SessionIndex) -> Vec<u8> {
1230 const MAGIC: [u8; 4] = *b"APPR";
1231
1232 (MAGIC, &self.0, session_index).encode()
1233 }
1234}
1235
1236#[derive(Clone, RuntimeDebug)]
1238pub struct ApprovalVoteMultipleCandidates<'a>(pub &'a [CandidateHash]);
1239
1240impl<'a> ApprovalVoteMultipleCandidates<'a> {
1241 pub fn signing_payload(&self, session_index: SessionIndex) -> Vec<u8> {
1243 const MAGIC: [u8; 4] = *b"APPR";
1244 if self.0.len() == 1 {
1249 (MAGIC, self.0.first().expect("QED: we just checked"), session_index).encode()
1250 } else {
1251 (MAGIC, &self.0, session_index).encode()
1252 }
1253 }
1254}
1255
1256#[derive(
1258 RuntimeDebug,
1259 Copy,
1260 Clone,
1261 PartialEq,
1262 Encode,
1263 Decode,
1264 DecodeWithMemTracking,
1265 TypeInfo,
1266 serde::Serialize,
1267 serde::Deserialize,
1268)]
1269pub struct ApprovalVotingParams {
1270 pub max_approval_coalesce_count: u32,
1275}
1276
1277impl Default for ApprovalVotingParams {
1278 fn default() -> Self {
1279 Self { max_approval_coalesce_count: 1 }
1280 }
1281}
1282
1283#[repr(u8)]
1285pub enum ValidityError {
1286 InvalidEthereumSignature = 0,
1288 SignerHasNoClaim = 1,
1290 NoPermission = 2,
1292 InvalidStatement = 3,
1294}
1295
1296impl From<ValidityError> for u8 {
1297 fn from(err: ValidityError) -> Self {
1298 err as u8
1299 }
1300}
1301
1302#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1305#[cfg_attr(feature = "std", derive(PartialEq))]
1306pub struct AbridgedHostConfiguration {
1307 pub max_code_size: u32,
1309 pub max_head_data_size: u32,
1311 pub max_upward_queue_count: u32,
1313 pub max_upward_queue_size: u32,
1317 pub max_upward_message_size: u32,
1321 pub max_upward_message_num_per_candidate: u32,
1325 pub hrmp_max_message_num_per_candidate: u32,
1329 pub validation_upgrade_cooldown: BlockNumber,
1331 pub validation_upgrade_delay: BlockNumber,
1333 pub async_backing_params: AsyncBackingParams,
1335}
1336
1337#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1340#[cfg_attr(feature = "std", derive(PartialEq))]
1341pub struct AbridgedHrmpChannel {
1342 pub max_capacity: u32,
1344 pub max_total_size: u32,
1346 pub max_message_size: u32,
1348 pub msg_count: u32,
1351 pub total_size: u32,
1354 pub mqc_head: Option<Hash>,
1362}
1363
1364#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
1366pub enum UpgradeRestriction {
1367 #[codec(index = 0)]
1370 Present,
1371}
1372
1373#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
1379pub enum UpgradeGoAhead {
1380 #[codec(index = 0)]
1389 Abort,
1390 #[codec(index = 1)]
1394 GoAhead,
1395}
1396
1397pub const POLKADOT_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"POL1";
1399
1400#[derive(Decode, Encode, Clone, PartialEq, Eq)]
1402pub enum ConsensusLog {
1403 #[codec(index = 1)]
1405 ParaUpgradeCode(Id, ValidationCodeHash),
1406 #[codec(index = 2)]
1408 ParaScheduleUpgradeCode(Id, ValidationCodeHash, BlockNumber),
1409 #[codec(index = 3)]
1412 ForceApprove(BlockNumber),
1413 #[codec(index = 4)]
1422 Revert(BlockNumber),
1423}
1424
1425impl ConsensusLog {
1426 pub fn from_digest_item(
1428 digest_item: &sp_runtime::DigestItem,
1429 ) -> Result<Option<Self>, codec::Error> {
1430 match digest_item {
1431 sp_runtime::DigestItem::Consensus(id, encoded) if id == &POLKADOT_ENGINE_ID =>
1432 Ok(Some(Self::decode(&mut &encoded[..])?)),
1433 _ => Ok(None),
1434 }
1435 }
1436}
1437
1438impl From<ConsensusLog> for sp_runtime::DigestItem {
1439 fn from(c: ConsensusLog) -> sp_runtime::DigestItem {
1440 Self::Consensus(POLKADOT_ENGINE_ID, c.encode())
1441 }
1442}
1443
1444#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1448pub enum DisputeStatement {
1449 #[codec(index = 0)]
1451 Valid(ValidDisputeStatementKind),
1452 #[codec(index = 1)]
1454 Invalid(InvalidDisputeStatementKind),
1455}
1456
1457impl DisputeStatement {
1458 pub fn payload_data(
1463 &self,
1464 candidate_hash: CandidateHash,
1465 session: SessionIndex,
1466 ) -> Result<Vec<u8>, ()> {
1467 match self {
1468 DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) =>
1469 Ok(ExplicitDisputeStatement { valid: true, candidate_hash, session }
1470 .signing_payload()),
1471 DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded(
1472 inclusion_parent,
1473 )) => Ok(CompactStatement::Seconded(candidate_hash).signing_payload(&SigningContext {
1474 session_index: session,
1475 parent_hash: *inclusion_parent,
1476 })),
1477 DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent)) =>
1478 Ok(CompactStatement::Valid(candidate_hash).signing_payload(&SigningContext {
1479 session_index: session,
1480 parent_hash: *inclusion_parent,
1481 })),
1482 DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) =>
1483 Ok(ApprovalVote(candidate_hash).signing_payload(session)),
1484 DisputeStatement::Valid(
1485 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes),
1486 ) =>
1487 if candidate_hashes.contains(&candidate_hash) {
1488 Ok(ApprovalVoteMultipleCandidates(candidate_hashes).signing_payload(session))
1489 } else {
1490 Err(())
1491 },
1492 DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit) =>
1493 Ok(ExplicitDisputeStatement { valid: false, candidate_hash, session }
1494 .signing_payload()),
1495 }
1496 }
1497
1498 pub fn check_signature(
1500 &self,
1501 validator_public: &ValidatorId,
1502 candidate_hash: CandidateHash,
1503 session: SessionIndex,
1504 validator_signature: &ValidatorSignature,
1505 ) -> Result<(), ()> {
1506 let payload = self.payload_data(candidate_hash, session)?;
1507
1508 if validator_signature.verify(&payload[..], &validator_public) {
1509 Ok(())
1510 } else {
1511 Err(())
1512 }
1513 }
1514
1515 pub fn indicates_validity(&self) -> bool {
1517 match *self {
1518 DisputeStatement::Valid(_) => true,
1519 DisputeStatement::Invalid(_) => false,
1520 }
1521 }
1522
1523 pub fn indicates_invalidity(&self) -> bool {
1525 match *self {
1526 DisputeStatement::Valid(_) => false,
1527 DisputeStatement::Invalid(_) => true,
1528 }
1529 }
1530
1531 pub fn is_backing(&self) -> bool {
1533 match self {
1534 Self::Valid(s) => s.is_backing(),
1535 Self::Invalid(_) => false,
1536 }
1537 }
1538}
1539
1540#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1542pub enum ValidDisputeStatementKind {
1543 #[codec(index = 0)]
1545 Explicit,
1546 #[codec(index = 1)]
1548 BackingSeconded(Hash),
1549 #[codec(index = 2)]
1551 BackingValid(Hash),
1552 #[codec(index = 3)]
1554 ApprovalChecking,
1555 #[codec(index = 4)]
1560 ApprovalCheckingMultipleCandidates(Vec<CandidateHash>),
1561}
1562
1563impl ValidDisputeStatementKind {
1564 pub fn is_backing(&self) -> bool {
1566 match self {
1567 ValidDisputeStatementKind::BackingSeconded(_) |
1568 ValidDisputeStatementKind::BackingValid(_) => true,
1569 ValidDisputeStatementKind::Explicit |
1570 ValidDisputeStatementKind::ApprovalChecking |
1571 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(_) => false,
1572 }
1573 }
1574}
1575
1576#[derive(Encode, Decode, DecodeWithMemTracking, Copy, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1578pub enum InvalidDisputeStatementKind {
1579 #[codec(index = 0)]
1581 Explicit,
1582}
1583
1584#[derive(Clone, PartialEq, RuntimeDebug)]
1586pub struct ExplicitDisputeStatement {
1587 pub valid: bool,
1589 pub candidate_hash: CandidateHash,
1591 pub session: SessionIndex,
1593}
1594
1595impl ExplicitDisputeStatement {
1596 pub fn signing_payload(&self) -> Vec<u8> {
1598 const MAGIC: [u8; 4] = *b"DISP";
1599
1600 (MAGIC, self.valid, self.candidate_hash, self.session).encode()
1601 }
1602}
1603
1604#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1606pub struct DisputeStatementSet {
1607 pub candidate_hash: CandidateHash,
1609 pub session: SessionIndex,
1611 pub statements: Vec<(DisputeStatement, ValidatorIndex, ValidatorSignature)>,
1613}
1614
1615impl From<CheckedDisputeStatementSet> for DisputeStatementSet {
1616 fn from(other: CheckedDisputeStatementSet) -> Self {
1617 other.0
1618 }
1619}
1620
1621impl AsRef<DisputeStatementSet> for DisputeStatementSet {
1622 fn as_ref(&self) -> &DisputeStatementSet {
1623 &self
1624 }
1625}
1626
1627pub type MultiDisputeStatementSet = Vec<DisputeStatementSet>;
1629
1630#[derive(Clone, PartialEq, RuntimeDebug, Encode)]
1632pub struct CheckedDisputeStatementSet(DisputeStatementSet);
1633
1634impl AsRef<DisputeStatementSet> for CheckedDisputeStatementSet {
1635 fn as_ref(&self) -> &DisputeStatementSet {
1636 &self.0
1637 }
1638}
1639
1640impl core::cmp::PartialEq<DisputeStatementSet> for CheckedDisputeStatementSet {
1641 fn eq(&self, other: &DisputeStatementSet) -> bool {
1642 self.0.eq(other)
1643 }
1644}
1645
1646impl CheckedDisputeStatementSet {
1647 pub fn unchecked_from_unchecked(unchecked: DisputeStatementSet) -> Self {
1650 Self(unchecked)
1651 }
1652}
1653
1654pub type CheckedMultiDisputeStatementSet = Vec<CheckedDisputeStatementSet>;
1656
1657#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, TypeInfo)]
1659pub struct DisputeState<N = BlockNumber> {
1660 pub validators_for: BitVec<u8, bitvec::order::Lsb0>, pub validators_against: BitVec<u8, bitvec::order::Lsb0>, pub start: N,
1666 pub concluded_at: Option<N>,
1668}
1669
1670#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1672pub struct InherentData<HDR: HeaderT = Header> {
1673 pub bitfields: UncheckedSignedAvailabilityBitfields,
1675 pub backed_candidates: Vec<BackedCandidate<HDR::Hash>>,
1677 pub disputes: MultiDisputeStatementSet,
1679 pub parent_header: HDR,
1681}
1682
1683#[derive(Clone, Eq, PartialEq, Decode, DecodeWithMemTracking, Encode, RuntimeDebug, TypeInfo)]
1686pub enum ValidityAttestation {
1687 #[codec(index = 1)]
1690 Implicit(ValidatorSignature),
1691 #[codec(index = 2)]
1694 Explicit(ValidatorSignature),
1695}
1696
1697impl ValidityAttestation {
1698 pub fn to_compact_statement(&self, candidate_hash: CandidateHash) -> CompactStatement {
1701 match *self {
1705 ValidityAttestation::Implicit(_) => CompactStatement::Seconded(candidate_hash),
1706 ValidityAttestation::Explicit(_) => CompactStatement::Valid(candidate_hash),
1707 }
1708 }
1709
1710 pub fn signature(&self) -> &ValidatorSignature {
1712 match *self {
1713 ValidityAttestation::Implicit(ref sig) => sig,
1714 ValidityAttestation::Explicit(ref sig) => sig,
1715 }
1716 }
1717
1718 pub fn signed_payload<H: Encode>(
1721 &self,
1722 candidate_hash: CandidateHash,
1723 signing_context: &SigningContext<H>,
1724 ) -> Vec<u8> {
1725 match *self {
1726 ValidityAttestation::Implicit(_) =>
1727 (CompactStatement::Seconded(candidate_hash), signing_context).encode(),
1728 ValidityAttestation::Explicit(_) =>
1729 (CompactStatement::Valid(candidate_hash), signing_context).encode(),
1730 }
1731 }
1732}
1733
1734#[derive(Clone, Eq, PartialEq, Default, Decode, Encode, RuntimeDebug)]
1736pub struct SigningContext<H = Hash> {
1737 pub session_index: sp_staking::SessionIndex,
1739 pub parent_hash: H,
1741}
1742
1743const BACKING_STATEMENT_MAGIC: [u8; 4] = *b"BKNG";
1744
1745#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
1748#[cfg_attr(feature = "std", derive(Hash))]
1749pub enum CompactStatement {
1750 Seconded(CandidateHash),
1752 Valid(CandidateHash),
1754}
1755
1756impl CompactStatement {
1757 pub fn signing_payload(&self, context: &SigningContext) -> Vec<u8> {
1760 (self, context).encode()
1761 }
1762
1763 pub fn candidate_hash(&self) -> &CandidateHash {
1765 match *self {
1766 CompactStatement::Seconded(ref h) | CompactStatement::Valid(ref h) => h,
1767 }
1768 }
1769}
1770
1771#[derive(Encode, Decode, TypeInfo)]
1773enum CompactStatementInner {
1774 #[codec(index = 1)]
1775 Seconded(CandidateHash),
1776 #[codec(index = 2)]
1777 Valid(CandidateHash),
1778}
1779
1780impl From<CompactStatement> for CompactStatementInner {
1781 fn from(s: CompactStatement) -> Self {
1782 match s {
1783 CompactStatement::Seconded(h) => CompactStatementInner::Seconded(h),
1784 CompactStatement::Valid(h) => CompactStatementInner::Valid(h),
1785 }
1786 }
1787}
1788
1789impl codec::Encode for CompactStatement {
1790 fn size_hint(&self) -> usize {
1791 4 + 1 + 32
1793 }
1794
1795 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
1796 dest.write(&BACKING_STATEMENT_MAGIC);
1797 CompactStatementInner::from(self.clone()).encode_to(dest)
1798 }
1799}
1800
1801impl codec::Decode for CompactStatement {
1802 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
1803 let maybe_magic = <[u8; 4]>::decode(input)?;
1804 if maybe_magic != BACKING_STATEMENT_MAGIC {
1805 return Err(codec::Error::from("invalid magic string"))
1806 }
1807
1808 Ok(match CompactStatementInner::decode(input)? {
1809 CompactStatementInner::Seconded(h) => CompactStatement::Seconded(h),
1810 CompactStatementInner::Valid(h) => CompactStatement::Valid(h),
1811 })
1812 }
1813}
1814
1815#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1817#[cfg_attr(feature = "std", derive(PartialEq))]
1818pub struct IndexedVec<K, V>(Vec<V>, PhantomData<fn(K) -> K>);
1819
1820impl<K, V> Default for IndexedVec<K, V> {
1821 fn default() -> Self {
1822 Self(vec![], PhantomData)
1823 }
1824}
1825
1826impl<K, V> From<Vec<V>> for IndexedVec<K, V> {
1827 fn from(validators: Vec<V>) -> Self {
1828 Self(validators, PhantomData)
1829 }
1830}
1831
1832impl<K, V> FromIterator<V> for IndexedVec<K, V> {
1833 fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
1834 Self(Vec::from_iter(iter), PhantomData)
1835 }
1836}
1837
1838impl<K, V> IndexedVec<K, V>
1839where
1840 V: Clone,
1841{
1842 pub fn get(&self, index: K) -> Option<&V>
1844 where
1845 K: TypeIndex,
1846 {
1847 self.0.get(index.type_index())
1848 }
1849
1850 pub fn get_mut(&mut self, index: K) -> Option<&mut V>
1852 where
1853 K: TypeIndex,
1854 {
1855 self.0.get_mut(index.type_index())
1856 }
1857
1858 pub fn len(&self) -> usize {
1860 self.0.len()
1861 }
1862
1863 pub fn to_vec(&self) -> Vec<V> {
1865 self.0.clone()
1866 }
1867
1868 pub fn iter(&self) -> Iter<'_, V> {
1870 self.0.iter()
1871 }
1872
1873 pub fn iter_mut(&mut self) -> IterMut<'_, V> {
1875 self.0.iter_mut()
1876 }
1877
1878 pub fn into_iter(self) -> IntoIter<V> {
1880 self.0.into_iter()
1881 }
1882
1883 pub fn is_empty(&self) -> bool {
1885 self.0.is_empty()
1886 }
1887}
1888
1889pub const fn byzantine_threshold(n: usize) -> usize {
1893 n.saturating_sub(1) / 3
1894}
1895
1896pub const fn supermajority_threshold(n: usize) -> usize {
1899 n - byzantine_threshold(n)
1900}
1901
1902pub fn effective_minimum_backing_votes(
1904 group_len: usize,
1905 configured_minimum_backing_votes: u32,
1906) -> usize {
1907 core::cmp::min(group_len, configured_minimum_backing_votes as usize)
1908}
1909
1910#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1915#[cfg_attr(feature = "std", derive(PartialEq))]
1916pub struct SessionInfo {
1917 pub active_validator_indices: Vec<ValidatorIndex>,
1921 pub random_seed: [u8; 32],
1923 pub dispute_period: SessionIndex,
1925
1926 pub validators: IndexedVec<ValidatorIndex, ValidatorId>,
1935 pub discovery_keys: Vec<AuthorityDiscoveryId>,
1942 pub assignment_keys: Vec<AssignmentId>,
1953 pub validator_groups: IndexedVec<GroupIndex, Vec<ValidatorIndex>>,
1957 pub n_cores: u32,
1959 pub zeroth_delay_tranche_width: u32,
1961 pub relay_vrf_modulo_samples: u32,
1963 pub n_delay_tranches: u32,
1965 pub no_show_slots: u32,
1968 pub needed_approvals: u32,
1970}
1971
1972#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1975pub struct PvfCheckStatement {
1976 pub accept: bool,
1978 pub subject: ValidationCodeHash,
1980 pub session_index: SessionIndex,
1982 pub validator_index: ValidatorIndex,
1984}
1985
1986impl PvfCheckStatement {
1987 pub fn signing_payload(&self) -> Vec<u8> {
1992 const MAGIC: [u8; 4] = *b"VCPC"; (MAGIC, self.accept, self.subject, self.session_index, self.validator_index).encode()
1994 }
1995}
1996
1997pub struct WellKnownKey<T> {
2001 pub key: Vec<u8>,
2003 _p: core::marker::PhantomData<T>,
2004}
2005
2006impl<T> From<Vec<u8>> for WellKnownKey<T> {
2007 fn from(key: Vec<u8>) -> Self {
2008 Self { key, _p: Default::default() }
2009 }
2010}
2011
2012impl<T> AsRef<[u8]> for WellKnownKey<T> {
2013 fn as_ref(&self) -> &[u8] {
2014 self.key.as_ref()
2015 }
2016}
2017
2018impl<T: Decode> WellKnownKey<T> {
2019 pub fn get(&self) -> Option<T> {
2021 sp_io::storage::get(&self.key)
2022 .and_then(|raw| codec::DecodeAll::decode_all(&mut raw.as_ref()).ok())
2023 }
2024}
2025
2026impl<T: Encode> WellKnownKey<T> {
2027 pub fn set(&self, value: T) {
2029 sp_io::storage::set(&self.key, &value.encode());
2030 }
2031}
2032
2033#[derive(
2035 Encode,
2036 Decode,
2037 DecodeWithMemTracking,
2038 TypeInfo,
2039 Clone,
2040 Copy,
2041 Debug,
2042 PartialEq,
2043 Eq,
2044 Serialize,
2045 Deserialize,
2046)]
2047pub enum PvfPrepKind {
2048 Precheck,
2050
2051 Prepare,
2053}
2054
2055#[derive(
2057 Encode,
2058 Decode,
2059 DecodeWithMemTracking,
2060 TypeInfo,
2061 Clone,
2062 Copy,
2063 Debug,
2064 PartialEq,
2065 Eq,
2066 Serialize,
2067 Deserialize,
2068)]
2069pub enum PvfExecKind {
2070 Backing,
2072 Approval,
2074}
2075
2076pub type NodeFeatures = BitVec<u8, bitvec::order::Lsb0>;
2078
2079pub mod node_features {
2081 #[repr(u8)]
2084 #[derive(Clone, Copy)]
2085 pub enum FeatureIndex {
2086 EnableAssignmentsV2 = 0,
2089 ElasticScalingMVP = 1,
2093 AvailabilityChunkMapping = 2,
2099 CandidateReceiptV2 = 3,
2103 FirstUnassigned = 4,
2107 }
2108}
2109
2110#[derive(
2112 RuntimeDebug,
2113 Copy,
2114 Clone,
2115 PartialEq,
2116 Encode,
2117 Decode,
2118 DecodeWithMemTracking,
2119 TypeInfo,
2120 serde::Serialize,
2121 serde::Deserialize,
2122)]
2123pub struct SchedulerParams<BlockNumber> {
2124 pub group_rotation_frequency: BlockNumber,
2128 pub paras_availability_period: BlockNumber,
2143 pub max_validators_per_core: Option<u32>,
2147 pub lookahead: u32,
2149 pub num_cores: u32,
2151 #[deprecated]
2154 pub max_availability_timeouts: u32,
2155 pub on_demand_queue_max_size: u32,
2157 pub on_demand_target_queue_utilization: Perbill,
2159 pub on_demand_fee_variability: Perbill,
2162 pub on_demand_base_fee: Balance,
2164 #[deprecated]
2167 pub ttl: BlockNumber,
2168}
2169
2170impl<BlockNumber: Default + From<u32>> Default for SchedulerParams<BlockNumber> {
2171 #[allow(deprecated)]
2172 fn default() -> Self {
2173 Self {
2174 group_rotation_frequency: 1u32.into(),
2175 paras_availability_period: 1u32.into(),
2176 max_validators_per_core: Default::default(),
2177 lookahead: 1,
2178 num_cores: Default::default(),
2179 max_availability_timeouts: Default::default(),
2180 on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE,
2181 on_demand_target_queue_utilization: Perbill::from_percent(25),
2182 on_demand_fee_variability: Perbill::from_percent(3),
2183 on_demand_base_fee: 10_000_000u128,
2184 ttl: 5u32.into(),
2185 }
2186 }
2187}
2188
2189#[cfg(test)]
2190pub mod tests {
2192 use super::*;
2193 use bitvec::bitvec;
2194 use sp_core::sr25519;
2195
2196 pub fn dummy_committed_candidate_receipt() -> CommittedCandidateReceipt {
2198 let zeros = Hash::zero();
2199
2200 CommittedCandidateReceipt {
2201 descriptor: CandidateDescriptor {
2202 para_id: 0.into(),
2203 relay_parent: zeros,
2204 collator: CollatorId::from(sr25519::Public::default()),
2205 persisted_validation_data_hash: zeros,
2206 pov_hash: zeros,
2207 erasure_root: zeros,
2208 signature: CollatorSignature::from(sr25519::Signature::default()),
2209 para_head: zeros,
2210 validation_code_hash: ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).hash(),
2211 },
2212 commitments: CandidateCommitments {
2213 head_data: HeadData(vec![]),
2214 upward_messages: vec![].try_into().expect("empty vec fits within bounds"),
2215 new_validation_code: None,
2216 horizontal_messages: vec![].try_into().expect("empty vec fits within bounds"),
2217 processed_downward_messages: 0,
2218 hrmp_watermark: 0_u32,
2219 },
2220 }
2221 }
2222
2223 #[test]
2224 fn group_rotation_info_calculations() {
2225 let info =
2226 GroupRotationInfo { session_start_block: 10u32, now: 15, group_rotation_frequency: 5 };
2227
2228 assert_eq!(info.next_rotation_at(), 20);
2229 assert_eq!(info.last_rotation_at(), 15);
2230 }
2231
2232 #[test]
2233 fn group_for_core_is_core_for_group() {
2234 for cores in 1..=256 {
2235 for rotations in 0..(cores * 2) {
2236 let info = GroupRotationInfo {
2237 session_start_block: 0u32,
2238 now: rotations,
2239 group_rotation_frequency: 1,
2240 };
2241
2242 for core in 0..cores {
2243 let group = info.group_for_core(CoreIndex(core), cores as usize);
2244 assert_eq!(info.core_for_group(group, cores as usize).0, core);
2245 }
2246 }
2247 }
2248 }
2249
2250 #[test]
2251 fn collator_signature_payload_is_valid() {
2252 let h = Hash::default();
2254 assert_eq!(h.as_ref().len(), 32);
2255
2256 let _payload = collator_signature_payload(
2257 &Hash::repeat_byte(1),
2258 &5u32.into(),
2259 &Hash::repeat_byte(2),
2260 &Hash::repeat_byte(3),
2261 &Hash::repeat_byte(4).into(),
2262 );
2263 }
2264
2265 #[test]
2266 fn test_byzantine_threshold() {
2267 assert_eq!(byzantine_threshold(0), 0);
2268 assert_eq!(byzantine_threshold(1), 0);
2269 assert_eq!(byzantine_threshold(2), 0);
2270 assert_eq!(byzantine_threshold(3), 0);
2271 assert_eq!(byzantine_threshold(4), 1);
2272 assert_eq!(byzantine_threshold(5), 1);
2273 assert_eq!(byzantine_threshold(6), 1);
2274 assert_eq!(byzantine_threshold(7), 2);
2275 }
2276
2277 #[test]
2278 fn test_supermajority_threshold() {
2279 assert_eq!(supermajority_threshold(0), 0);
2280 assert_eq!(supermajority_threshold(1), 1);
2281 assert_eq!(supermajority_threshold(2), 2);
2282 assert_eq!(supermajority_threshold(3), 3);
2283 assert_eq!(supermajority_threshold(4), 3);
2284 assert_eq!(supermajority_threshold(5), 4);
2285 assert_eq!(supermajority_threshold(6), 5);
2286 assert_eq!(supermajority_threshold(7), 5);
2287 }
2288
2289 #[test]
2290 fn balance_bigger_than_usize() {
2291 let zero_b: Balance = 0;
2292 let zero_u: usize = 0;
2293
2294 assert!(zero_b.leading_zeros() >= zero_u.leading_zeros());
2295 }
2296
2297 #[test]
2298 fn test_backed_candidate_injected_core_index() {
2299 let initial_validator_indices = bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1];
2300 let mut candidate = BackedCandidate::new(
2301 dummy_committed_candidate_receipt(),
2302 vec![],
2303 initial_validator_indices.clone(),
2304 CoreIndex(10),
2305 );
2306
2307 candidate
2309 .set_validator_indices_and_core_index(initial_validator_indices.clone().into(), None);
2310 let (validator_indices, core_index) = candidate.validator_indices_and_core_index();
2311 assert_eq!(validator_indices, initial_validator_indices.as_bitslice());
2312 assert!(core_index.is_none());
2313
2314 candidate.set_validator_indices_and_core_index(
2317 bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1, 0, 1, 0, 1, 0].into(),
2318 None,
2319 );
2320
2321 let (validator_indices, core_index) = candidate.validator_indices_and_core_index();
2322 assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0].as_bitslice());
2323 assert!(core_index.is_some());
2324
2325 let mut candidate = BackedCandidate::new(
2327 dummy_committed_candidate_receipt(),
2328 vec![],
2329 bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1],
2330 CoreIndex(10),
2331 );
2332 let (validator_indices, core_index) = candidate.validator_indices_and_core_index();
2333 assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1]);
2334 assert_eq!(core_index, Some(CoreIndex(10)));
2335
2336 let encoded_validator_indices = candidate.validator_indices.clone();
2337 candidate.set_validator_indices_and_core_index(validator_indices.into(), core_index);
2338 assert_eq!(candidate.validator_indices, encoded_validator_indices);
2339 }
2340}