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 const AUTHORITIES: &[u8] =
249 &hex!["1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d"];
250
251 pub const NEXT_AUTHORITIES: &[u8] =
256 &hex!["1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c"];
257
258 pub fn para_head(para_id: Id) -> Vec<u8> {
262 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c3"];
263
264 para_id.using_encoded(|para_id: &[u8]| {
265 prefix
266 .as_ref()
267 .iter()
268 .chain(twox_64(para_id).iter())
269 .chain(para_id.iter())
270 .cloned()
271 .collect()
272 })
273 }
274
275 #[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
282 pub fn relay_dispatch_queue_size(para_id: Id) -> Vec<u8> {
283 let prefix = hex!["f5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e"];
284
285 para_id.using_encoded(|para_id: &[u8]| {
286 prefix
287 .as_ref()
288 .iter()
289 .chain(twox_64(para_id).iter())
290 .chain(para_id.iter())
291 .cloned()
292 .collect()
293 })
294 }
295
296 #[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
298 pub fn relay_dispatch_queue_size_typed(para: Id) -> WellKnownKey<(u32, u32)> {
299 #[allow(deprecated)]
300 relay_dispatch_queue_size(para).into()
301 }
302
303 pub fn relay_dispatch_queue_remaining_capacity(para_id: Id) -> WellKnownKey<(u32, u32)> {
311 (b":relay_dispatch_queue_remaining_capacity", para_id).encode().into()
312 }
313
314 pub fn hrmp_channels(channel: HrmpChannelId) -> Vec<u8> {
318 let prefix = hex!["6a0da05ca59913bc38a8630590f2627cb6604cff828a6e3f579ca6c59ace013d"];
319
320 channel.using_encoded(|channel: &[u8]| {
321 prefix
322 .as_ref()
323 .iter()
324 .chain(twox_64(channel).iter())
325 .chain(channel.iter())
326 .cloned()
327 .collect()
328 })
329 }
330
331 pub fn hrmp_ingress_channel_index(para_id: Id) -> Vec<u8> {
335 let prefix = hex!["6a0da05ca59913bc38a8630590f2627c1d3719f5b0b12c7105c073c507445948"];
336
337 para_id.using_encoded(|para_id: &[u8]| {
338 prefix
339 .as_ref()
340 .iter()
341 .chain(twox_64(para_id).iter())
342 .chain(para_id.iter())
343 .cloned()
344 .collect()
345 })
346 }
347
348 pub fn hrmp_egress_channel_index(para_id: Id) -> Vec<u8> {
352 let prefix = hex!["6a0da05ca59913bc38a8630590f2627cf12b746dcf32e843354583c9702cc020"];
353
354 para_id.using_encoded(|para_id: &[u8]| {
355 prefix
356 .as_ref()
357 .iter()
358 .chain(twox_64(para_id).iter())
359 .chain(para_id.iter())
360 .cloned()
361 .collect()
362 })
363 }
364
365 pub fn dmq_mqc_head(para_id: Id) -> Vec<u8> {
370 let prefix = hex!["63f78c98723ddc9073523ef3beefda0c4d7fefc408aac59dbfe80a72ac8e3ce5"];
371
372 para_id.using_encoded(|para_id: &[u8]| {
373 prefix
374 .as_ref()
375 .iter()
376 .chain(twox_64(para_id).iter())
377 .chain(para_id.iter())
378 .cloned()
379 .collect()
380 })
381 }
382
383 pub fn upgrade_go_ahead_signal(para_id: Id) -> Vec<u8> {
388 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1949e94c040f5e73d9b7addd6cb603d15d3"];
389
390 para_id.using_encoded(|para_id: &[u8]| {
391 prefix
392 .as_ref()
393 .iter()
394 .chain(twox_64(para_id).iter())
395 .chain(para_id.iter())
396 .cloned()
397 .collect()
398 })
399 }
400
401 pub fn upgrade_restriction_signal(para_id: Id) -> Vec<u8> {
406 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa194f27bbb460270642b5bcaf032ea04d56a"];
407
408 para_id.using_encoded(|para_id: &[u8]| {
409 prefix
410 .as_ref()
411 .iter()
412 .chain(twox_64(para_id).iter())
413 .chain(para_id.iter())
414 .cloned()
415 .collect()
416 })
417 }
418}
419
420pub const PARACHAINS_INHERENT_IDENTIFIER: InherentIdentifier = *b"parachn0";
422
423pub const ASSIGNMENT_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"asgn");
425
426pub const MIN_CODE_SIZE: u32 = 9;
428
429pub const MAX_CODE_SIZE: u32 = 3 * 1024 * 1024;
439
440pub const MAX_HEAD_DATA_SIZE: u32 = 1 * 1024 * 1024;
447
448pub const MAX_POV_SIZE: u32 = 10 * 1024 * 1024;
456
457pub const ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE: u32 = 10_000;
461
462pub const ON_DEMAND_MAX_QUEUE_MAX_SIZE: u32 = 1_000_000_000;
468
469pub const LEGACY_MIN_BACKING_VOTES: u32 = 2;
472
473pub const DEFAULT_SCHEDULING_LOOKAHEAD: u32 = 3;
475
476mod assignment_app {
479 use sp_application_crypto::{app_crypto, sr25519};
480 app_crypto!(sr25519, super::ASSIGNMENT_KEY_TYPE_ID);
481}
482
483pub type AssignmentId = assignment_app::Public;
486
487sp_application_crypto::with_pair! {
488 pub type AssignmentPair = assignment_app::Pair;
491}
492
493pub type CandidateIndex = u32;
495
496pub fn collator_signature_payload<H: AsRef<[u8]>>(
498 relay_parent: &H,
499 para_id: &Id,
500 persisted_validation_data_hash: &Hash,
501 pov_hash: &Hash,
502 validation_code_hash: &ValidationCodeHash,
503) -> [u8; 132] {
504 let mut payload = [0u8; 132];
506
507 payload[0..32].copy_from_slice(relay_parent.as_ref());
508 u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s));
509 payload[36..68].copy_from_slice(persisted_validation_data_hash.as_ref());
510 payload[68..100].copy_from_slice(pov_hash.as_ref());
511 payload[100..132].copy_from_slice(validation_code_hash.as_ref());
512
513 payload
514}
515
516pub(crate) fn check_collator_signature<H: AsRef<[u8]>>(
517 relay_parent: &H,
518 para_id: &Id,
519 persisted_validation_data_hash: &Hash,
520 pov_hash: &Hash,
521 validation_code_hash: &ValidationCodeHash,
522 collator: &CollatorId,
523 signature: &CollatorSignature,
524) -> Result<(), ()> {
525 let payload = collator_signature_payload(
526 relay_parent,
527 para_id,
528 persisted_validation_data_hash,
529 pov_hash,
530 validation_code_hash,
531 );
532
533 if signature.verify(&payload[..], collator) {
534 Ok(())
535 } else {
536 Err(())
537 }
538}
539
540#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
542#[cfg_attr(feature = "std", derive(Hash))]
543pub struct CandidateDescriptor<H = Hash> {
544 pub para_id: Id,
546 pub relay_parent: H,
548 pub collator: CollatorId,
550 pub persisted_validation_data_hash: Hash,
554 pub pov_hash: Hash,
556 pub erasure_root: Hash,
558 pub signature: CollatorSignature,
561 pub para_head: Hash,
563 pub validation_code_hash: ValidationCodeHash,
565}
566
567impl<H: AsRef<[u8]>> CandidateDescriptor<H> {
568 pub fn check_collator_signature(&self) -> Result<(), ()> {
570 check_collator_signature(
571 &self.relay_parent,
572 &self.para_id,
573 &self.persisted_validation_data_hash,
574 &self.pov_hash,
575 &self.validation_code_hash,
576 &self.collator,
577 &self.signature,
578 )
579 }
580}
581
582#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
584pub struct CandidateReceipt<H = Hash> {
585 pub descriptor: CandidateDescriptor<H>,
587 pub commitments_hash: Hash,
589}
590
591impl<H> CandidateReceipt<H> {
592 pub fn descriptor(&self) -> &CandidateDescriptor<H> {
594 &self.descriptor
595 }
596
597 pub fn hash(&self) -> CandidateHash
599 where
600 H: Encode,
601 {
602 CandidateHash(BlakeTwo256::hash_of(self))
603 }
604}
605
606#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
608#[cfg_attr(feature = "std", derive(Hash))]
609pub struct CommittedCandidateReceipt<H = Hash> {
610 pub descriptor: CandidateDescriptor<H>,
612 pub commitments: CandidateCommitments,
614}
615
616impl<H> CommittedCandidateReceipt<H> {
617 pub fn descriptor(&self) -> &CandidateDescriptor<H> {
619 &self.descriptor
620 }
621}
622
623impl<H: Clone> CommittedCandidateReceipt<H> {
624 pub fn to_plain(&self) -> CandidateReceipt<H> {
626 CandidateReceipt {
627 descriptor: self.descriptor.clone(),
628 commitments_hash: self.commitments.hash(),
629 }
630 }
631
632 pub fn hash(&self) -> CandidateHash
637 where
638 H: Encode,
639 {
640 self.to_plain().hash()
641 }
642
643 pub fn corresponds_to(&self, receipt: &CandidateReceipt<H>) -> bool
645 where
646 H: PartialEq,
647 {
648 receipt.descriptor == self.descriptor && receipt.commitments_hash == self.commitments.hash()
649 }
650}
651
652impl PartialOrd for CommittedCandidateReceipt {
653 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
654 Some(self.cmp(other))
655 }
656}
657
658impl Ord for CommittedCandidateReceipt {
659 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
660 self.descriptor()
663 .para_id
664 .cmp(&other.descriptor().para_id)
665 .then_with(|| self.commitments.head_data.cmp(&other.commitments.head_data))
666 }
667}
668
669#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
691#[cfg_attr(feature = "std", derive(Default))]
692pub struct PersistedValidationData<H = Hash, N = BlockNumber> {
693 pub parent_head: HeadData,
695 pub relay_parent_number: N,
697 pub relay_parent_storage_root: H,
699 pub max_pov_size: u32,
701}
702
703impl<H: Encode, N: Encode> PersistedValidationData<H, N> {
704 pub fn hash(&self) -> Hash {
706 BlakeTwo256::hash_of(self)
707 }
708}
709
710#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
712#[cfg_attr(feature = "std", derive(Default, Hash))]
713pub struct CandidateCommitments<N = BlockNumber> {
714 pub upward_messages: UpwardMessages,
716 pub horizontal_messages: HorizontalMessages,
718 pub new_validation_code: Option<ValidationCode>,
720 pub head_data: HeadData,
722 pub processed_downward_messages: u32,
724 pub hrmp_watermark: N,
727}
728
729impl CandidateCommitments {
730 pub fn hash(&self) -> Hash {
732 BlakeTwo256::hash_of(self)
733 }
734}
735
736#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, RuntimeDebug, TypeInfo)]
740pub struct AvailabilityBitfield(pub BitVec<u8, bitvec::order::Lsb0>);
741
742impl From<BitVec<u8, bitvec::order::Lsb0>> for AvailabilityBitfield {
743 fn from(inner: BitVec<u8, bitvec::order::Lsb0>) -> Self {
744 AvailabilityBitfield(inner)
745 }
746}
747
748pub type SignedStatement = Signed<CompactStatement>;
750pub type UncheckedSignedStatement = UncheckedSigned<CompactStatement>;
752
753pub type SignedAvailabilityBitfield = Signed<AvailabilityBitfield>;
755pub type UncheckedSignedAvailabilityBitfield = UncheckedSigned<AvailabilityBitfield>;
757
758pub type SignedAvailabilityBitfields = Vec<SignedAvailabilityBitfield>;
760pub type UncheckedSignedAvailabilityBitfields = Vec<UncheckedSignedAvailabilityBitfield>;
763
764#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
766pub struct BackedCandidate<H = Hash> {
767 candidate: CommittedCandidateReceipt<H>,
769 validity_votes: Vec<ValidityAttestation>,
771 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
774}
775
776impl<H> BackedCandidate<H> {
777 pub fn new(
779 candidate: CommittedCandidateReceipt<H>,
780 validity_votes: Vec<ValidityAttestation>,
781 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
782 core_index: CoreIndex,
783 ) -> Self {
784 let mut instance = Self { candidate, validity_votes, validator_indices };
785 instance.inject_core_index(core_index);
786 instance
787 }
788
789 pub fn descriptor(&self) -> &CandidateDescriptor<H> {
791 &self.candidate.descriptor
792 }
793
794 pub fn candidate(&self) -> &CommittedCandidateReceipt<H> {
796 &self.candidate
797 }
798
799 pub fn validity_votes(&self) -> &[ValidityAttestation] {
801 &self.validity_votes
802 }
803
804 pub fn validity_votes_mut(&mut self) -> &mut Vec<ValidityAttestation> {
806 &mut self.validity_votes
807 }
808
809 pub fn hash(&self) -> CandidateHash
811 where
812 H: Clone + Encode,
813 {
814 self.candidate.hash()
815 }
816
817 pub fn receipt(&self) -> CandidateReceipt<H>
819 where
820 H: Clone,
821 {
822 self.candidate.to_plain()
823 }
824
825 pub fn validator_indices_and_core_index(
827 &self,
828 ) -> (&BitSlice<u8, bitvec::order::Lsb0>, Option<CoreIndex>) {
829 let core_idx_offset = self.validator_indices.len().saturating_sub(8);
831 if core_idx_offset > 0 {
832 let (validator_indices_slice, core_idx_slice) =
833 self.validator_indices.split_at(core_idx_offset);
834 return (validator_indices_slice, Some(CoreIndex(core_idx_slice.load::<u8>() as u32)));
835 }
836
837 (&self.validator_indices, None)
838 }
839
840 fn inject_core_index(&mut self, core_index: CoreIndex) {
842 let core_index_to_inject: BitVec<u8, bitvec::order::Lsb0> =
843 BitVec::from_vec(vec![core_index.0 as u8]);
844 self.validator_indices.extend(core_index_to_inject);
845 }
846
847 pub fn set_validator_indices_and_core_index(
849 &mut self,
850 new_indices: BitVec<u8, bitvec::order::Lsb0>,
851 maybe_core_index: Option<CoreIndex>,
852 ) {
853 self.validator_indices = new_indices;
854
855 if let Some(core_index) = maybe_core_index {
856 self.inject_core_index(core_index);
857 }
858 }
859}
860
861pub fn check_candidate_backing<H: AsRef<[u8]> + Clone + Encode + core::fmt::Debug>(
872 candidate_hash: CandidateHash,
873 validity_votes: &[ValidityAttestation],
874 validator_indices: &BitSlice<u8, bitvec::order::Lsb0>,
875 signing_context: &SigningContext<H>,
876 group_len: usize,
877 validator_lookup: impl Fn(usize) -> Option<ValidatorId>,
878) -> Result<usize, ()> {
879 if validator_indices.len() != group_len {
880 log::debug!(
881 target: LOG_TARGET,
882 "Check candidate backing: indices mismatch: group_len = {} , indices_len = {}",
883 group_len,
884 validator_indices.len(),
885 );
886 return Err(())
887 }
888
889 if validity_votes.len() > group_len {
890 log::debug!(
891 target: LOG_TARGET,
892 "Check candidate backing: Too many votes, expected: {}, found: {}",
893 group_len,
894 validity_votes.len(),
895 );
896 return Err(())
897 }
898
899 let mut signed = 0;
900 for ((val_in_group_idx, _), attestation) in validator_indices
901 .iter()
902 .enumerate()
903 .filter(|(_, signed)| **signed)
904 .zip(validity_votes.iter())
905 {
906 let validator_id = validator_lookup(val_in_group_idx).ok_or(())?;
907 let payload = attestation.signed_payload(candidate_hash, signing_context);
908 let sig = attestation.signature();
909
910 if sig.verify(&payload[..], &validator_id) {
911 signed += 1;
912 } else {
913 log::debug!(
914 target: LOG_TARGET,
915 "Check candidate backing: Invalid signature. validator_id = {:?}, validator_index = {} ",
916 validator_id,
917 val_in_group_idx,
918 );
919 return Err(())
920 }
921 }
922
923 if signed != validity_votes.len() {
924 log::error!(
925 target: LOG_TARGET,
926 "Check candidate backing: Too many signatures, expected = {}, found = {}",
927 validity_votes.len(),
928 signed,
929 );
930 return Err(())
931 }
932
933 Ok(signed)
934}
935
936#[derive(
938 Encode,
939 Decode,
940 DecodeWithMemTracking,
941 Default,
942 PartialOrd,
943 Ord,
944 Eq,
945 PartialEq,
946 Clone,
947 Copy,
948 TypeInfo,
949 RuntimeDebug,
950)]
951#[cfg_attr(feature = "std", derive(Hash))]
952pub struct CoreIndex(pub u32);
953
954impl From<u32> for CoreIndex {
955 fn from(i: u32) -> CoreIndex {
956 CoreIndex(i)
957 }
958}
959
960impl TypeIndex for CoreIndex {
961 fn type_index(&self) -> usize {
962 self.0 as usize
963 }
964}
965
966#[derive(
968 Encode,
969 Decode,
970 DecodeWithMemTracking,
971 Default,
972 Clone,
973 Copy,
974 Debug,
975 PartialEq,
976 Eq,
977 TypeInfo,
978 PartialOrd,
979 Ord,
980)]
981#[cfg_attr(feature = "std", derive(Hash))]
982pub struct GroupIndex(pub u32);
983
984impl From<u32> for GroupIndex {
985 fn from(i: u32) -> GroupIndex {
986 GroupIndex(i)
987 }
988}
989
990impl TypeIndex for GroupIndex {
991 fn type_index(&self) -> usize {
992 self.0 as usize
993 }
994}
995
996#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
998pub struct ParathreadClaim(pub Id, pub Option<CollatorId>);
999
1000#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
1002pub struct ParathreadEntry {
1003 pub claim: ParathreadClaim,
1005 pub retries: u32,
1007}
1008
1009#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1011#[cfg_attr(feature = "std", derive(PartialEq))]
1012pub struct GroupRotationInfo<N = BlockNumber> {
1013 pub session_start_block: N,
1015 pub group_rotation_frequency: N,
1017 pub now: N,
1019}
1020
1021impl GroupRotationInfo {
1022 pub fn group_for_core(&self, core_index: CoreIndex, cores: usize) -> GroupIndex {
1027 if self.group_rotation_frequency == 0 {
1028 return GroupIndex(core_index.0)
1029 }
1030 if cores == 0 {
1031 return GroupIndex(0)
1032 }
1033
1034 let cores = core::cmp::min(cores, u32::MAX as usize);
1035 let blocks_since_start = self.now.saturating_sub(self.session_start_block);
1036 let rotations = blocks_since_start / self.group_rotation_frequency;
1037
1038 let idx = (core_index.0 as usize + rotations as usize) % cores;
1041 GroupIndex(idx as u32)
1042 }
1043
1044 pub fn core_for_group(&self, group_index: GroupIndex, cores: usize) -> CoreIndex {
1049 if self.group_rotation_frequency == 0 {
1050 return CoreIndex(group_index.0)
1051 }
1052 if cores == 0 {
1053 return CoreIndex(0)
1054 }
1055
1056 let cores = core::cmp::min(cores, u32::MAX as usize);
1057 let blocks_since_start = self.now.saturating_sub(self.session_start_block);
1058 let rotations = blocks_since_start / self.group_rotation_frequency;
1059 let rotations = rotations % cores as u32;
1060
1061 let idx = (group_index.0 as usize + cores - rotations as usize) % cores;
1067 CoreIndex(idx as u32)
1068 }
1069
1070 pub fn bump_rotation(&self) -> Self {
1072 GroupRotationInfo {
1073 session_start_block: self.session_start_block,
1074 group_rotation_frequency: self.group_rotation_frequency,
1075 now: self.next_rotation_at(),
1076 }
1077 }
1078}
1079
1080impl<N: Saturating + BaseArithmetic + Copy> GroupRotationInfo<N> {
1081 pub fn next_rotation_at(&self) -> N {
1084 let cycle_once = self.now + self.group_rotation_frequency;
1085 cycle_once -
1086 (cycle_once.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
1087 }
1088
1089 pub fn last_rotation_at(&self) -> N {
1092 self.now -
1093 (self.now.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
1094 }
1095}
1096
1097#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1099#[cfg_attr(feature = "std", derive(PartialEq))]
1100pub struct OccupiedCore<H = Hash, N = BlockNumber> {
1101 pub next_up_on_available: Option<ScheduledCore>,
1105 pub occupied_since: N,
1107 pub time_out_at: N,
1109 pub next_up_on_time_out: Option<ScheduledCore>,
1113 pub availability: BitVec<u8, bitvec::order::Lsb0>,
1117 pub group_responsible: GroupIndex,
1119 pub candidate_hash: CandidateHash,
1121 pub candidate_descriptor: CandidateDescriptor<H>,
1123}
1124
1125impl<H, N> OccupiedCore<H, N> {
1126 pub fn para_id(&self) -> Id {
1128 self.candidate_descriptor.para_id
1129 }
1130}
1131
1132#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1134#[cfg_attr(feature = "std", derive(PartialEq))]
1135pub struct ScheduledCore {
1136 pub para_id: Id,
1138 pub collator: Option<CollatorId>,
1142}
1143
1144#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1146#[cfg_attr(feature = "std", derive(PartialEq))]
1147pub enum CoreState<H = Hash, N = BlockNumber> {
1148 #[codec(index = 0)]
1150 Occupied(OccupiedCore<H, N>),
1151 #[codec(index = 1)]
1157 Scheduled(ScheduledCore),
1158 #[codec(index = 2)]
1162 Free,
1163}
1164
1165impl<N> CoreState<N> {
1166 #[deprecated(
1171 note = "`para_id` will be removed. Use `ClaimQueue` to query the scheduled `para_id` instead."
1172 )]
1173 pub fn para_id(&self) -> Option<Id> {
1174 match self {
1175 Self::Occupied(ref core) => core.next_up_on_available.as_ref().map(|n| n.para_id),
1176 Self::Scheduled(core) => Some(core.para_id),
1177 Self::Free => None,
1178 }
1179 }
1180
1181 pub fn is_occupied(&self) -> bool {
1183 matches!(self, Self::Occupied(_))
1184 }
1185}
1186
1187#[derive(Clone, Copy, Encode, Decode, TypeInfo, RuntimeDebug)]
1189#[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash))]
1190pub enum OccupiedCoreAssumption {
1191 #[codec(index = 0)]
1193 Included,
1194 #[codec(index = 1)]
1196 TimedOut,
1197 #[codec(index = 2)]
1199 Free,
1200}
1201
1202#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
1204#[cfg_attr(feature = "std", derive(PartialEq))]
1205pub enum CandidateEvent<H = Hash> {
1206 #[codec(index = 0)]
1209 CandidateBacked(CandidateReceipt<H>, HeadData, CoreIndex, GroupIndex),
1210 #[codec(index = 1)]
1214 CandidateIncluded(CandidateReceipt<H>, HeadData, CoreIndex, GroupIndex),
1215 #[codec(index = 2)]
1218 CandidateTimedOut(CandidateReceipt<H>, HeadData, CoreIndex),
1219}
1220
1221#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1223#[cfg_attr(feature = "std", derive(PartialEq))]
1224pub struct ScrapedOnChainVotes<H: Encode + Decode = Hash> {
1225 pub session: SessionIndex,
1227 pub backing_validators_per_candidate:
1230 Vec<(CandidateReceipt<H>, Vec<(ValidatorIndex, ValidityAttestation)>)>,
1231 pub disputes: MultiDisputeStatementSet,
1235}
1236
1237#[derive(Clone, RuntimeDebug)]
1239pub struct ApprovalVote(pub CandidateHash);
1240
1241impl ApprovalVote {
1242 pub fn signing_payload(&self, session_index: SessionIndex) -> Vec<u8> {
1244 const MAGIC: [u8; 4] = *b"APPR";
1245
1246 (MAGIC, &self.0, session_index).encode()
1247 }
1248}
1249
1250#[derive(Clone, RuntimeDebug)]
1252pub struct ApprovalVoteMultipleCandidates<'a>(pub &'a [CandidateHash]);
1253
1254impl<'a> ApprovalVoteMultipleCandidates<'a> {
1255 pub fn signing_payload(&self, session_index: SessionIndex) -> Vec<u8> {
1257 const MAGIC: [u8; 4] = *b"APPR";
1258 if self.0.len() == 1 {
1263 (MAGIC, self.0.first().expect("QED: we just checked"), session_index).encode()
1264 } else {
1265 (MAGIC, &self.0, session_index).encode()
1266 }
1267 }
1268}
1269
1270#[derive(
1272 RuntimeDebug,
1273 Copy,
1274 Clone,
1275 PartialEq,
1276 Encode,
1277 Decode,
1278 DecodeWithMemTracking,
1279 TypeInfo,
1280 serde::Serialize,
1281 serde::Deserialize,
1282)]
1283pub struct ApprovalVotingParams {
1284 pub max_approval_coalesce_count: u32,
1289}
1290
1291impl Default for ApprovalVotingParams {
1292 fn default() -> Self {
1293 Self { max_approval_coalesce_count: 1 }
1294 }
1295}
1296
1297#[repr(u8)]
1299pub enum ValidityError {
1300 InvalidEthereumSignature = 0,
1302 SignerHasNoClaim = 1,
1304 NoPermission = 2,
1306 InvalidStatement = 3,
1308}
1309
1310impl From<ValidityError> for u8 {
1311 fn from(err: ValidityError) -> Self {
1312 err as u8
1313 }
1314}
1315
1316#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1319#[cfg_attr(feature = "std", derive(PartialEq))]
1320pub struct AbridgedHostConfiguration {
1321 pub max_code_size: u32,
1323 pub max_head_data_size: u32,
1325 pub max_upward_queue_count: u32,
1327 pub max_upward_queue_size: u32,
1331 pub max_upward_message_size: u32,
1335 pub max_upward_message_num_per_candidate: u32,
1339 pub hrmp_max_message_num_per_candidate: u32,
1343 pub validation_upgrade_cooldown: BlockNumber,
1345 pub validation_upgrade_delay: BlockNumber,
1347 pub async_backing_params: AsyncBackingParams,
1349}
1350
1351#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1354#[cfg_attr(feature = "std", derive(Default, PartialEq))]
1355pub struct AbridgedHrmpChannel {
1356 pub max_capacity: u32,
1358 pub max_total_size: u32,
1360 pub max_message_size: u32,
1362 pub msg_count: u32,
1365 pub total_size: u32,
1368 pub mqc_head: Option<Hash>,
1376}
1377
1378#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
1380pub enum UpgradeRestriction {
1381 #[codec(index = 0)]
1384 Present,
1385}
1386
1387#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
1393pub enum UpgradeGoAhead {
1394 #[codec(index = 0)]
1403 Abort,
1404 #[codec(index = 1)]
1408 GoAhead,
1409}
1410
1411pub const POLKADOT_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"POL1";
1413
1414#[derive(Decode, Encode, Clone, PartialEq, Eq)]
1416pub enum ConsensusLog {
1417 #[codec(index = 1)]
1419 ParaUpgradeCode(Id, ValidationCodeHash),
1420 #[codec(index = 2)]
1422 ParaScheduleUpgradeCode(Id, ValidationCodeHash, BlockNumber),
1423 #[codec(index = 3)]
1426 ForceApprove(BlockNumber),
1427 #[codec(index = 4)]
1436 Revert(BlockNumber),
1437}
1438
1439impl ConsensusLog {
1440 pub fn from_digest_item(
1442 digest_item: &sp_runtime::DigestItem,
1443 ) -> Result<Option<Self>, codec::Error> {
1444 match digest_item {
1445 sp_runtime::DigestItem::Consensus(id, encoded) if id == &POLKADOT_ENGINE_ID =>
1446 Ok(Some(Self::decode(&mut &encoded[..])?)),
1447 _ => Ok(None),
1448 }
1449 }
1450}
1451
1452impl From<ConsensusLog> for sp_runtime::DigestItem {
1453 fn from(c: ConsensusLog) -> sp_runtime::DigestItem {
1454 Self::Consensus(POLKADOT_ENGINE_ID, c.encode())
1455 }
1456}
1457
1458#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1462pub enum DisputeStatement {
1463 #[codec(index = 0)]
1465 Valid(ValidDisputeStatementKind),
1466 #[codec(index = 1)]
1468 Invalid(InvalidDisputeStatementKind),
1469}
1470
1471impl DisputeStatement {
1472 pub fn payload_data(
1477 &self,
1478 candidate_hash: CandidateHash,
1479 session: SessionIndex,
1480 ) -> Result<Vec<u8>, ()> {
1481 match self {
1482 DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) =>
1483 Ok(ExplicitDisputeStatement { valid: true, candidate_hash, session }
1484 .signing_payload()),
1485 DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded(
1486 inclusion_parent,
1487 )) => Ok(CompactStatement::Seconded(candidate_hash).signing_payload(&SigningContext {
1488 session_index: session,
1489 parent_hash: *inclusion_parent,
1490 })),
1491 DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent)) =>
1492 Ok(CompactStatement::Valid(candidate_hash).signing_payload(&SigningContext {
1493 session_index: session,
1494 parent_hash: *inclusion_parent,
1495 })),
1496 DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) =>
1497 Ok(ApprovalVote(candidate_hash).signing_payload(session)),
1498 DisputeStatement::Valid(
1499 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes),
1500 ) =>
1501 if candidate_hashes.contains(&candidate_hash) {
1502 Ok(ApprovalVoteMultipleCandidates(candidate_hashes).signing_payload(session))
1503 } else {
1504 Err(())
1505 },
1506 DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit) =>
1507 Ok(ExplicitDisputeStatement { valid: false, candidate_hash, session }
1508 .signing_payload()),
1509 }
1510 }
1511
1512 pub fn check_signature(
1514 &self,
1515 validator_public: &ValidatorId,
1516 candidate_hash: CandidateHash,
1517 session: SessionIndex,
1518 validator_signature: &ValidatorSignature,
1519 ) -> Result<(), ()> {
1520 let payload = self.payload_data(candidate_hash, session)?;
1521
1522 if validator_signature.verify(&payload[..], &validator_public) {
1523 Ok(())
1524 } else {
1525 Err(())
1526 }
1527 }
1528
1529 pub fn indicates_validity(&self) -> bool {
1531 match *self {
1532 DisputeStatement::Valid(_) => true,
1533 DisputeStatement::Invalid(_) => false,
1534 }
1535 }
1536
1537 pub fn indicates_invalidity(&self) -> bool {
1539 match *self {
1540 DisputeStatement::Valid(_) => false,
1541 DisputeStatement::Invalid(_) => true,
1542 }
1543 }
1544
1545 pub fn is_backing(&self) -> bool {
1547 match self {
1548 Self::Valid(s) => s.is_backing(),
1549 Self::Invalid(_) => false,
1550 }
1551 }
1552}
1553
1554#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1556pub enum ValidDisputeStatementKind {
1557 #[codec(index = 0)]
1559 Explicit,
1560 #[codec(index = 1)]
1562 BackingSeconded(Hash),
1563 #[codec(index = 2)]
1565 BackingValid(Hash),
1566 #[codec(index = 3)]
1568 ApprovalChecking,
1569 #[codec(index = 4)]
1574 ApprovalCheckingMultipleCandidates(Vec<CandidateHash>),
1575}
1576
1577impl ValidDisputeStatementKind {
1578 pub fn is_backing(&self) -> bool {
1580 match self {
1581 ValidDisputeStatementKind::BackingSeconded(_) |
1582 ValidDisputeStatementKind::BackingValid(_) => true,
1583 ValidDisputeStatementKind::Explicit |
1584 ValidDisputeStatementKind::ApprovalChecking |
1585 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(_) => false,
1586 }
1587 }
1588}
1589
1590#[derive(Encode, Decode, DecodeWithMemTracking, Copy, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1592pub enum InvalidDisputeStatementKind {
1593 #[codec(index = 0)]
1595 Explicit,
1596}
1597
1598#[derive(Clone, PartialEq, RuntimeDebug)]
1600pub struct ExplicitDisputeStatement {
1601 pub valid: bool,
1603 pub candidate_hash: CandidateHash,
1605 pub session: SessionIndex,
1607}
1608
1609impl ExplicitDisputeStatement {
1610 pub fn signing_payload(&self) -> Vec<u8> {
1612 const MAGIC: [u8; 4] = *b"DISP";
1613
1614 (MAGIC, self.valid, self.candidate_hash, self.session).encode()
1615 }
1616}
1617
1618#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1620pub struct DisputeStatementSet {
1621 pub candidate_hash: CandidateHash,
1623 pub session: SessionIndex,
1625 pub statements: Vec<(DisputeStatement, ValidatorIndex, ValidatorSignature)>,
1627}
1628
1629impl From<CheckedDisputeStatementSet> for DisputeStatementSet {
1630 fn from(other: CheckedDisputeStatementSet) -> Self {
1631 other.0
1632 }
1633}
1634
1635impl AsRef<DisputeStatementSet> for DisputeStatementSet {
1636 fn as_ref(&self) -> &DisputeStatementSet {
1637 &self
1638 }
1639}
1640
1641pub type MultiDisputeStatementSet = Vec<DisputeStatementSet>;
1643
1644#[derive(Clone, PartialEq, RuntimeDebug, Encode)]
1646pub struct CheckedDisputeStatementSet(DisputeStatementSet);
1647
1648impl AsRef<DisputeStatementSet> for CheckedDisputeStatementSet {
1649 fn as_ref(&self) -> &DisputeStatementSet {
1650 &self.0
1651 }
1652}
1653
1654impl core::cmp::PartialEq<DisputeStatementSet> for CheckedDisputeStatementSet {
1655 fn eq(&self, other: &DisputeStatementSet) -> bool {
1656 self.0.eq(other)
1657 }
1658}
1659
1660impl CheckedDisputeStatementSet {
1661 pub fn unchecked_from_unchecked(unchecked: DisputeStatementSet) -> Self {
1664 Self(unchecked)
1665 }
1666}
1667
1668pub type CheckedMultiDisputeStatementSet = Vec<CheckedDisputeStatementSet>;
1670
1671#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, TypeInfo)]
1673pub struct DisputeState<N = BlockNumber> {
1674 pub validators_for: BitVec<u8, bitvec::order::Lsb0>, pub validators_against: BitVec<u8, bitvec::order::Lsb0>, pub start: N,
1680 pub concluded_at: Option<N>,
1682}
1683
1684#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1686pub struct InherentData<HDR: HeaderT = Header> {
1687 pub bitfields: UncheckedSignedAvailabilityBitfields,
1689 pub backed_candidates: Vec<BackedCandidate<HDR::Hash>>,
1691 pub disputes: MultiDisputeStatementSet,
1693 pub parent_header: HDR,
1695}
1696
1697#[derive(Clone, Eq, PartialEq, Decode, DecodeWithMemTracking, Encode, RuntimeDebug, TypeInfo)]
1700pub enum ValidityAttestation {
1701 #[codec(index = 1)]
1704 Implicit(ValidatorSignature),
1705 #[codec(index = 2)]
1708 Explicit(ValidatorSignature),
1709}
1710
1711impl ValidityAttestation {
1712 pub fn to_compact_statement(&self, candidate_hash: CandidateHash) -> CompactStatement {
1715 match *self {
1719 ValidityAttestation::Implicit(_) => CompactStatement::Seconded(candidate_hash),
1720 ValidityAttestation::Explicit(_) => CompactStatement::Valid(candidate_hash),
1721 }
1722 }
1723
1724 pub fn signature(&self) -> &ValidatorSignature {
1726 match *self {
1727 ValidityAttestation::Implicit(ref sig) => sig,
1728 ValidityAttestation::Explicit(ref sig) => sig,
1729 }
1730 }
1731
1732 pub fn signed_payload<H: Encode>(
1735 &self,
1736 candidate_hash: CandidateHash,
1737 signing_context: &SigningContext<H>,
1738 ) -> Vec<u8> {
1739 match *self {
1740 ValidityAttestation::Implicit(_) =>
1741 (CompactStatement::Seconded(candidate_hash), signing_context).encode(),
1742 ValidityAttestation::Explicit(_) =>
1743 (CompactStatement::Valid(candidate_hash), signing_context).encode(),
1744 }
1745 }
1746}
1747
1748#[derive(Clone, Eq, PartialEq, Default, Decode, Encode, RuntimeDebug)]
1750pub struct SigningContext<H = Hash> {
1751 pub session_index: sp_staking::SessionIndex,
1753 pub parent_hash: H,
1755}
1756
1757const BACKING_STATEMENT_MAGIC: [u8; 4] = *b"BKNG";
1758
1759#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
1762#[cfg_attr(feature = "std", derive(Hash))]
1763pub enum CompactStatement {
1764 Seconded(CandidateHash),
1766 Valid(CandidateHash),
1768}
1769
1770impl CompactStatement {
1771 pub fn signing_payload(&self, context: &SigningContext) -> Vec<u8> {
1774 (self, context).encode()
1775 }
1776
1777 pub fn candidate_hash(&self) -> &CandidateHash {
1779 match *self {
1780 CompactStatement::Seconded(ref h) | CompactStatement::Valid(ref h) => h,
1781 }
1782 }
1783}
1784
1785#[derive(Encode, Decode, TypeInfo)]
1787enum CompactStatementInner {
1788 #[codec(index = 1)]
1789 Seconded(CandidateHash),
1790 #[codec(index = 2)]
1791 Valid(CandidateHash),
1792}
1793
1794impl From<CompactStatement> for CompactStatementInner {
1795 fn from(s: CompactStatement) -> Self {
1796 match s {
1797 CompactStatement::Seconded(h) => CompactStatementInner::Seconded(h),
1798 CompactStatement::Valid(h) => CompactStatementInner::Valid(h),
1799 }
1800 }
1801}
1802
1803impl codec::Encode for CompactStatement {
1804 fn size_hint(&self) -> usize {
1805 4 + 1 + 32
1807 }
1808
1809 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
1810 dest.write(&BACKING_STATEMENT_MAGIC);
1811 CompactStatementInner::from(self.clone()).encode_to(dest)
1812 }
1813}
1814
1815impl codec::Decode for CompactStatement {
1816 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
1817 let maybe_magic = <[u8; 4]>::decode(input)?;
1818 if maybe_magic != BACKING_STATEMENT_MAGIC {
1819 return Err(codec::Error::from("invalid magic string"))
1820 }
1821
1822 Ok(match CompactStatementInner::decode(input)? {
1823 CompactStatementInner::Seconded(h) => CompactStatement::Seconded(h),
1824 CompactStatementInner::Valid(h) => CompactStatement::Valid(h),
1825 })
1826 }
1827}
1828
1829#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1831#[cfg_attr(feature = "std", derive(PartialEq))]
1832pub struct IndexedVec<K, V>(Vec<V>, PhantomData<fn(K) -> K>);
1833
1834impl<K, V> Default for IndexedVec<K, V> {
1835 fn default() -> Self {
1836 Self(vec![], PhantomData)
1837 }
1838}
1839
1840impl<K, V> From<Vec<V>> for IndexedVec<K, V> {
1841 fn from(validators: Vec<V>) -> Self {
1842 Self(validators, PhantomData)
1843 }
1844}
1845
1846impl<K, V> FromIterator<V> for IndexedVec<K, V> {
1847 fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
1848 Self(Vec::from_iter(iter), PhantomData)
1849 }
1850}
1851
1852impl<K, V> IndexedVec<K, V>
1853where
1854 V: Clone,
1855{
1856 pub fn get(&self, index: K) -> Option<&V>
1858 where
1859 K: TypeIndex,
1860 {
1861 self.0.get(index.type_index())
1862 }
1863
1864 pub fn get_mut(&mut self, index: K) -> Option<&mut V>
1866 where
1867 K: TypeIndex,
1868 {
1869 self.0.get_mut(index.type_index())
1870 }
1871
1872 pub fn len(&self) -> usize {
1874 self.0.len()
1875 }
1876
1877 pub fn to_vec(&self) -> Vec<V> {
1879 self.0.clone()
1880 }
1881
1882 pub fn iter(&self) -> Iter<'_, V> {
1884 self.0.iter()
1885 }
1886
1887 pub fn iter_mut(&mut self) -> IterMut<'_, V> {
1889 self.0.iter_mut()
1890 }
1891
1892 pub fn into_iter(self) -> IntoIter<V> {
1894 self.0.into_iter()
1895 }
1896
1897 pub fn is_empty(&self) -> bool {
1899 self.0.is_empty()
1900 }
1901}
1902
1903pub const fn byzantine_threshold(n: usize) -> usize {
1907 n.saturating_sub(1) / 3
1908}
1909
1910pub const fn supermajority_threshold(n: usize) -> usize {
1913 n - byzantine_threshold(n)
1914}
1915
1916pub fn effective_minimum_backing_votes(
1918 group_len: usize,
1919 configured_minimum_backing_votes: u32,
1920) -> usize {
1921 core::cmp::min(group_len, configured_minimum_backing_votes as usize)
1922}
1923
1924#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1929#[cfg_attr(feature = "std", derive(PartialEq))]
1930pub struct SessionInfo {
1931 pub active_validator_indices: Vec<ValidatorIndex>,
1935 pub random_seed: [u8; 32],
1937 pub dispute_period: SessionIndex,
1939
1940 pub validators: IndexedVec<ValidatorIndex, ValidatorId>,
1949 pub discovery_keys: Vec<AuthorityDiscoveryId>,
1956 pub assignment_keys: Vec<AssignmentId>,
1967 pub validator_groups: IndexedVec<GroupIndex, Vec<ValidatorIndex>>,
1971 pub n_cores: u32,
1973 pub zeroth_delay_tranche_width: u32,
1975 pub relay_vrf_modulo_samples: u32,
1977 pub n_delay_tranches: u32,
1979 pub no_show_slots: u32,
1982 pub needed_approvals: u32,
1984}
1985
1986#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1989pub struct PvfCheckStatement {
1990 pub accept: bool,
1992 pub subject: ValidationCodeHash,
1994 pub session_index: SessionIndex,
1996 pub validator_index: ValidatorIndex,
1998}
1999
2000impl PvfCheckStatement {
2001 pub fn signing_payload(&self) -> Vec<u8> {
2006 const MAGIC: [u8; 4] = *b"VCPC"; (MAGIC, self.accept, self.subject, self.session_index, self.validator_index).encode()
2008 }
2009}
2010
2011pub struct WellKnownKey<T> {
2015 pub key: Vec<u8>,
2017 _p: core::marker::PhantomData<T>,
2018}
2019
2020impl<T> From<Vec<u8>> for WellKnownKey<T> {
2021 fn from(key: Vec<u8>) -> Self {
2022 Self { key, _p: Default::default() }
2023 }
2024}
2025
2026impl<T> AsRef<[u8]> for WellKnownKey<T> {
2027 fn as_ref(&self) -> &[u8] {
2028 self.key.as_ref()
2029 }
2030}
2031
2032impl<T: Decode> WellKnownKey<T> {
2033 pub fn get(&self) -> Option<T> {
2035 sp_io::storage::get(&self.key)
2036 .and_then(|raw| codec::DecodeAll::decode_all(&mut raw.as_ref()).ok())
2037 }
2038}
2039
2040impl<T: Encode> WellKnownKey<T> {
2041 pub fn set(&self, value: T) {
2043 sp_io::storage::set(&self.key, &value.encode());
2044 }
2045}
2046
2047#[derive(
2049 Encode,
2050 Decode,
2051 DecodeWithMemTracking,
2052 TypeInfo,
2053 Clone,
2054 Copy,
2055 Debug,
2056 PartialEq,
2057 Eq,
2058 Serialize,
2059 Deserialize,
2060)]
2061pub enum PvfPrepKind {
2062 Precheck,
2064
2065 Prepare,
2067}
2068
2069#[derive(
2071 Encode,
2072 Decode,
2073 DecodeWithMemTracking,
2074 TypeInfo,
2075 Clone,
2076 Copy,
2077 Debug,
2078 PartialEq,
2079 Eq,
2080 Serialize,
2081 Deserialize,
2082)]
2083pub enum PvfExecKind {
2084 Backing,
2086 Approval,
2088}
2089
2090pub type NodeFeatures = BitVec<u8, bitvec::order::Lsb0>;
2092
2093pub mod node_features {
2095 #[repr(u8)]
2098 #[derive(Clone, Copy)]
2099 pub enum FeatureIndex {
2100 EnableAssignmentsV2 = 0,
2103 ElasticScalingMVP = 1,
2107 AvailabilityChunkMapping = 2,
2113 CandidateReceiptV2 = 3,
2117 FirstUnassigned = 4,
2121 }
2122}
2123
2124#[derive(
2126 RuntimeDebug,
2127 Copy,
2128 Clone,
2129 PartialEq,
2130 Encode,
2131 Decode,
2132 DecodeWithMemTracking,
2133 TypeInfo,
2134 serde::Serialize,
2135 serde::Deserialize,
2136)]
2137pub struct SchedulerParams<BlockNumber> {
2138 pub group_rotation_frequency: BlockNumber,
2142 pub paras_availability_period: BlockNumber,
2157 pub max_validators_per_core: Option<u32>,
2161 pub lookahead: u32,
2163 pub num_cores: u32,
2165 #[deprecated]
2168 pub max_availability_timeouts: u32,
2169 pub on_demand_queue_max_size: u32,
2171 pub on_demand_target_queue_utilization: Perbill,
2173 pub on_demand_fee_variability: Perbill,
2176 pub on_demand_base_fee: Balance,
2178 #[deprecated]
2181 pub ttl: BlockNumber,
2182}
2183
2184impl<BlockNumber: Default + From<u32>> Default for SchedulerParams<BlockNumber> {
2185 #[allow(deprecated)]
2186 fn default() -> Self {
2187 Self {
2188 group_rotation_frequency: 1u32.into(),
2189 paras_availability_period: 1u32.into(),
2190 max_validators_per_core: Default::default(),
2191 lookahead: 1,
2192 num_cores: Default::default(),
2193 max_availability_timeouts: Default::default(),
2194 on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE,
2195 on_demand_target_queue_utilization: Perbill::from_percent(25),
2196 on_demand_fee_variability: Perbill::from_percent(3),
2197 on_demand_base_fee: 10_000_000u128,
2198 ttl: 5u32.into(),
2199 }
2200 }
2201}
2202
2203#[cfg(test)]
2204pub mod tests {
2206 use super::*;
2207 use bitvec::bitvec;
2208 use sp_core::sr25519;
2209
2210 pub fn dummy_committed_candidate_receipt() -> CommittedCandidateReceipt {
2212 let zeros = Hash::zero();
2213
2214 CommittedCandidateReceipt {
2215 descriptor: CandidateDescriptor {
2216 para_id: 0.into(),
2217 relay_parent: zeros,
2218 collator: CollatorId::from(sr25519::Public::default()),
2219 persisted_validation_data_hash: zeros,
2220 pov_hash: zeros,
2221 erasure_root: zeros,
2222 signature: CollatorSignature::from(sr25519::Signature::default()),
2223 para_head: zeros,
2224 validation_code_hash: ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).hash(),
2225 },
2226 commitments: CandidateCommitments {
2227 head_data: HeadData(vec![]),
2228 upward_messages: vec![].try_into().expect("empty vec fits within bounds"),
2229 new_validation_code: None,
2230 horizontal_messages: vec![].try_into().expect("empty vec fits within bounds"),
2231 processed_downward_messages: 0,
2232 hrmp_watermark: 0_u32,
2233 },
2234 }
2235 }
2236
2237 #[test]
2238 fn group_rotation_info_calculations() {
2239 let info =
2240 GroupRotationInfo { session_start_block: 10u32, now: 15, group_rotation_frequency: 5 };
2241
2242 assert_eq!(info.next_rotation_at(), 20);
2243 assert_eq!(info.last_rotation_at(), 15);
2244 }
2245
2246 #[test]
2247 fn group_for_core_is_core_for_group() {
2248 for cores in 1..=256 {
2249 for rotations in 0..(cores * 2) {
2250 let info = GroupRotationInfo {
2251 session_start_block: 0u32,
2252 now: rotations,
2253 group_rotation_frequency: 1,
2254 };
2255
2256 for core in 0..cores {
2257 let group = info.group_for_core(CoreIndex(core), cores as usize);
2258 assert_eq!(info.core_for_group(group, cores as usize).0, core);
2259 }
2260 }
2261 }
2262 }
2263
2264 #[test]
2265 fn collator_signature_payload_is_valid() {
2266 let h = Hash::default();
2268 assert_eq!(h.as_ref().len(), 32);
2269
2270 let _payload = collator_signature_payload(
2271 &Hash::repeat_byte(1),
2272 &5u32.into(),
2273 &Hash::repeat_byte(2),
2274 &Hash::repeat_byte(3),
2275 &Hash::repeat_byte(4).into(),
2276 );
2277 }
2278
2279 #[test]
2280 fn test_byzantine_threshold() {
2281 assert_eq!(byzantine_threshold(0), 0);
2282 assert_eq!(byzantine_threshold(1), 0);
2283 assert_eq!(byzantine_threshold(2), 0);
2284 assert_eq!(byzantine_threshold(3), 0);
2285 assert_eq!(byzantine_threshold(4), 1);
2286 assert_eq!(byzantine_threshold(5), 1);
2287 assert_eq!(byzantine_threshold(6), 1);
2288 assert_eq!(byzantine_threshold(7), 2);
2289 }
2290
2291 #[test]
2292 fn test_supermajority_threshold() {
2293 assert_eq!(supermajority_threshold(0), 0);
2294 assert_eq!(supermajority_threshold(1), 1);
2295 assert_eq!(supermajority_threshold(2), 2);
2296 assert_eq!(supermajority_threshold(3), 3);
2297 assert_eq!(supermajority_threshold(4), 3);
2298 assert_eq!(supermajority_threshold(5), 4);
2299 assert_eq!(supermajority_threshold(6), 5);
2300 assert_eq!(supermajority_threshold(7), 5);
2301 }
2302
2303 #[test]
2304 fn balance_bigger_than_usize() {
2305 let zero_b: Balance = 0;
2306 let zero_u: usize = 0;
2307
2308 assert!(zero_b.leading_zeros() >= zero_u.leading_zeros());
2309 }
2310
2311 #[test]
2312 fn test_backed_candidate_injected_core_index() {
2313 let initial_validator_indices = bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1];
2314 let mut candidate = BackedCandidate::new(
2315 dummy_committed_candidate_receipt(),
2316 vec![],
2317 initial_validator_indices.clone(),
2318 CoreIndex(10),
2319 );
2320
2321 candidate
2323 .set_validator_indices_and_core_index(initial_validator_indices.clone().into(), None);
2324 let (validator_indices, core_index) = candidate.validator_indices_and_core_index();
2325 assert_eq!(validator_indices, initial_validator_indices.as_bitslice());
2326 assert!(core_index.is_none());
2327
2328 candidate.set_validator_indices_and_core_index(
2331 bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1, 0, 1, 0, 1, 0].into(),
2332 None,
2333 );
2334
2335 let (validator_indices, core_index) = candidate.validator_indices_and_core_index();
2336 assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0].as_bitslice());
2337 assert!(core_index.is_some());
2338
2339 let mut candidate = BackedCandidate::new(
2341 dummy_committed_candidate_receipt(),
2342 vec![],
2343 bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1],
2344 CoreIndex(10),
2345 );
2346 let (validator_indices, core_index) = candidate.validator_indices_and_core_index();
2347 assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1]);
2348 assert_eq!(core_index, Some(CoreIndex(10)));
2349
2350 let encoded_validator_indices = candidate.validator_indices.clone();
2351 candidate.set_validator_indices_and_core_index(validator_indices.into(), core_index);
2352 assert_eq!(candidate.validator_indices, encoded_validator_indices);
2353 }
2354}