1use alloc::{
20 collections::{BTreeMap, BTreeSet, VecDeque},
21 vec,
22 vec::{IntoIter, Vec},
23};
24
25use bitvec::{field::BitField, prelude::*, slice::BitSlice};
26
27use codec::{Decode, DecodeWithMemTracking, Encode};
28use scale_info::TypeInfo;
29
30use core::{
31 marker::PhantomData,
32 slice::{Iter, IterMut},
33};
34
35use sp_application_crypto::{ByteArray, KeyTypeId};
36use sp_arithmetic::{
37 traits::{BaseArithmetic, Saturating},
38 Perbill,
39};
40
41use bounded_collections::BoundedVec;
42use serde::{Deserialize, Serialize};
43use sp_core::{ConstU32, RuntimeDebug};
44use sp_inherents::InherentIdentifier;
45
46pub use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
51pub use sp_consensus_slots::Slot;
52pub use sp_runtime::traits::{AppVerify, BlakeTwo256, Hash as HashT, Header as HeaderT};
53pub use sp_staking::SessionIndex;
54
55pub use polkadot_core_primitives::v2::{
57 AccountId, AccountIndex, AccountPublic, Balance, Block, BlockId, BlockNumber, CandidateHash,
58 ChainId, DownwardMessage, Hash, Header, InboundDownwardMessage, InboundHrmpMessage, Moment,
59 Nonce, OutboundHrmpMessage, Remark, Signature, UncheckedExtrinsic,
60};
61
62pub use polkadot_parachain_primitives::primitives::{
64 HeadData, HorizontalMessages, HrmpChannelId, Id, Id as ParaId, UpwardMessage, UpwardMessages,
65 ValidationCode, ValidationCodeHash, LOWEST_PUBLIC_ID,
66};
67
68mod signed;
70pub use signed::{EncodeAs, Signed, UncheckedSigned};
71
72pub mod async_backing;
73pub mod executor_params;
74pub mod slashing;
75
76pub use async_backing::AsyncBackingParams;
77pub use executor_params::{
78 ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, ExecutorParamsPrepHash,
79};
80
81mod metrics;
82pub use metrics::{
83 metric_definitions, RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues,
84 RuntimeMetricLabels, RuntimeMetricOp, RuntimeMetricUpdate,
85};
86
87pub const COLLATOR_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"coll");
89const LOG_TARGET: &str = "runtime::primitives";
90
91mod collator_app {
92 use sp_application_crypto::{app_crypto, sr25519};
93 app_crypto!(sr25519, super::COLLATOR_KEY_TYPE_ID);
94}
95
96pub type CollatorId = collator_app::Public;
98
99#[cfg(feature = "std")]
101pub type CollatorPair = collator_app::Pair;
102
103pub type CollatorSignature = collator_app::Signature;
105
106pub const PARACHAIN_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"para");
108
109mod validator_app {
110 use sp_application_crypto::{app_crypto, sr25519};
111 app_crypto!(sr25519, super::PARACHAIN_KEY_TYPE_ID);
112}
113
114pub type ValidatorId = validator_app::Public;
119
120pub trait TypeIndex {
122 fn type_index(&self) -> usize;
124}
125
126#[derive(
129 Eq,
130 Ord,
131 PartialEq,
132 PartialOrd,
133 Copy,
134 Clone,
135 Encode,
136 Decode,
137 DecodeWithMemTracking,
138 TypeInfo,
139 RuntimeDebug,
140)]
141#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))]
142pub struct ValidatorIndex(pub u32);
143
144#[derive(Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
151#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))]
152pub struct ChunkIndex(pub u32);
153
154impl From<ChunkIndex> for ValidatorIndex {
155 fn from(c_index: ChunkIndex) -> Self {
156 ValidatorIndex(c_index.0)
157 }
158}
159
160impl From<ValidatorIndex> for ChunkIndex {
161 fn from(v_index: ValidatorIndex) -> Self {
162 ChunkIndex(v_index.0)
163 }
164}
165
166impl From<u32> for ChunkIndex {
167 fn from(n: u32) -> Self {
168 ChunkIndex(n)
169 }
170}
171
172impl From<u32> for ValidatorIndex {
174 fn from(n: u32) -> Self {
175 ValidatorIndex(n)
176 }
177}
178
179impl TypeIndex for ValidatorIndex {
180 fn type_index(&self) -> usize {
181 self.0 as usize
182 }
183}
184
185sp_application_crypto::with_pair! {
186 pub type ValidatorPair = validator_app::Pair;
188}
189
190pub type ValidatorSignature = validator_app::Signature;
195
196pub mod well_known_keys {
198 use super::{HrmpChannelId, Id, WellKnownKey};
199 use alloc::vec::Vec;
200 use codec::Encode as _;
201 use hex_literal::hex;
202 use sp_io::hashing::twox_64;
203
204 pub const EPOCH_INDEX: &[u8] =
220 &hex!["1cb6f36e027abb2091cfb5110ab5087f38316cbf8fa0da822a20ac1c55bf1be3"];
221
222 pub const CURRENT_BLOCK_RANDOMNESS: &[u8] =
226 &hex!["1cb6f36e027abb2091cfb5110ab5087fd077dfdb8adb10f78f10a5df8742c545"];
227
228 pub const ONE_EPOCH_AGO_RANDOMNESS: &[u8] =
232 &hex!["1cb6f36e027abb2091cfb5110ab5087f7ce678799d3eff024253b90e84927cc6"];
233
234 pub const TWO_EPOCHS_AGO_RANDOMNESS: &[u8] =
238 &hex!["1cb6f36e027abb2091cfb5110ab5087f7a414cb008e0e61e46722aa60abdd672"];
239
240 pub const CURRENT_SLOT: &[u8] =
244 &hex!["1cb6f36e027abb2091cfb5110ab5087f06155b3cd9a8c9e5e9a23fd5dc13a5ed"];
245
246 pub const ACTIVE_CONFIG: &[u8] =
250 &hex!["06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"];
251
252 pub const AUTHORITIES: &[u8] =
257 &hex!["1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d"];
258
259 pub const NEXT_AUTHORITIES: &[u8] =
264 &hex!["1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c"];
265
266 pub fn para_head(para_id: Id) -> Vec<u8> {
270 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c3"];
271
272 para_id.using_encoded(|para_id: &[u8]| {
273 prefix
274 .as_ref()
275 .iter()
276 .chain(twox_64(para_id).iter())
277 .chain(para_id.iter())
278 .cloned()
279 .collect()
280 })
281 }
282
283 #[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
290 pub fn relay_dispatch_queue_size(para_id: Id) -> Vec<u8> {
291 let prefix = hex!["f5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e"];
292
293 para_id.using_encoded(|para_id: &[u8]| {
294 prefix
295 .as_ref()
296 .iter()
297 .chain(twox_64(para_id).iter())
298 .chain(para_id.iter())
299 .cloned()
300 .collect()
301 })
302 }
303
304 #[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
306 pub fn relay_dispatch_queue_size_typed(para: Id) -> WellKnownKey<(u32, u32)> {
307 #[allow(deprecated)]
308 relay_dispatch_queue_size(para).into()
309 }
310
311 pub fn relay_dispatch_queue_remaining_capacity(para_id: Id) -> WellKnownKey<(u32, u32)> {
319 (b":relay_dispatch_queue_remaining_capacity", para_id).encode().into()
320 }
321
322 pub fn hrmp_channels(channel: HrmpChannelId) -> Vec<u8> {
326 let prefix = hex!["6a0da05ca59913bc38a8630590f2627cb6604cff828a6e3f579ca6c59ace013d"];
327
328 channel.using_encoded(|channel: &[u8]| {
329 prefix
330 .as_ref()
331 .iter()
332 .chain(twox_64(channel).iter())
333 .chain(channel.iter())
334 .cloned()
335 .collect()
336 })
337 }
338
339 pub fn hrmp_ingress_channel_index(para_id: Id) -> Vec<u8> {
343 let prefix = hex!["6a0da05ca59913bc38a8630590f2627c1d3719f5b0b12c7105c073c507445948"];
344
345 para_id.using_encoded(|para_id: &[u8]| {
346 prefix
347 .as_ref()
348 .iter()
349 .chain(twox_64(para_id).iter())
350 .chain(para_id.iter())
351 .cloned()
352 .collect()
353 })
354 }
355
356 pub fn hrmp_egress_channel_index(para_id: Id) -> Vec<u8> {
360 let prefix = hex!["6a0da05ca59913bc38a8630590f2627cf12b746dcf32e843354583c9702cc020"];
361
362 para_id.using_encoded(|para_id: &[u8]| {
363 prefix
364 .as_ref()
365 .iter()
366 .chain(twox_64(para_id).iter())
367 .chain(para_id.iter())
368 .cloned()
369 .collect()
370 })
371 }
372
373 pub fn dmq_mqc_head(para_id: Id) -> Vec<u8> {
378 let prefix = hex!["63f78c98723ddc9073523ef3beefda0c4d7fefc408aac59dbfe80a72ac8e3ce5"];
379
380 para_id.using_encoded(|para_id: &[u8]| {
381 prefix
382 .as_ref()
383 .iter()
384 .chain(twox_64(para_id).iter())
385 .chain(para_id.iter())
386 .cloned()
387 .collect()
388 })
389 }
390
391 pub fn upgrade_go_ahead_signal(para_id: Id) -> Vec<u8> {
396 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1949e94c040f5e73d9b7addd6cb603d15d3"];
397
398 para_id.using_encoded(|para_id: &[u8]| {
399 prefix
400 .as_ref()
401 .iter()
402 .chain(twox_64(para_id).iter())
403 .chain(para_id.iter())
404 .cloned()
405 .collect()
406 })
407 }
408
409 pub fn upgrade_restriction_signal(para_id: Id) -> Vec<u8> {
414 let prefix = hex!["cd710b30bd2eab0352ddcc26417aa194f27bbb460270642b5bcaf032ea04d56a"];
415
416 para_id.using_encoded(|para_id: &[u8]| {
417 prefix
418 .as_ref()
419 .iter()
420 .chain(twox_64(para_id).iter())
421 .chain(para_id.iter())
422 .cloned()
423 .collect()
424 })
425 }
426}
427
428pub const PARACHAINS_INHERENT_IDENTIFIER: InherentIdentifier = *b"parachn0";
430
431pub const ASSIGNMENT_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"asgn");
433
434pub const MIN_CODE_SIZE: u32 = 9;
436
437pub const MAX_CODE_SIZE: u32 = 3 * 1024 * 1024;
447
448pub const MAX_HEAD_DATA_SIZE: u32 = 1 * 1024 * 1024;
455
456pub const MAX_POV_SIZE: u32 = 10 * 1024 * 1024;
464
465pub const ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE: u32 = 10_000;
469
470pub const ON_DEMAND_MAX_QUEUE_MAX_SIZE: u32 = 1_000_000_000;
476
477pub const LEGACY_MIN_BACKING_VOTES: u32 = 2;
480
481pub const DEFAULT_SCHEDULING_LOOKAHEAD: u32 = 3;
483
484mod assignment_app {
487 use sp_application_crypto::{app_crypto, sr25519};
488 app_crypto!(sr25519, super::ASSIGNMENT_KEY_TYPE_ID);
489}
490
491pub type AssignmentId = assignment_app::Public;
494
495sp_application_crypto::with_pair! {
496 pub type AssignmentPair = assignment_app::Pair;
499}
500
501pub type CandidateIndex = u32;
503
504#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
526#[cfg_attr(feature = "std", derive(Default))]
527pub struct PersistedValidationData<H = Hash, N = BlockNumber> {
528 pub parent_head: HeadData,
530 pub relay_parent_number: N,
532 pub relay_parent_storage_root: H,
534 pub max_pov_size: u32,
536}
537
538impl<H: Encode, N: Encode> PersistedValidationData<H, N> {
539 pub fn hash(&self) -> Hash {
541 BlakeTwo256::hash_of(self)
542 }
543}
544
545#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
547#[cfg_attr(feature = "std", derive(Default, Hash))]
548pub struct CandidateCommitments<N = BlockNumber> {
549 pub upward_messages: UpwardMessages,
551 pub horizontal_messages: HorizontalMessages,
553 pub new_validation_code: Option<ValidationCode>,
555 pub head_data: HeadData,
557 pub processed_downward_messages: u32,
559 pub hrmp_watermark: N,
562}
563
564impl CandidateCommitments {
565 pub fn hash(&self) -> Hash {
567 BlakeTwo256::hash_of(self)
568 }
569}
570
571#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, RuntimeDebug, TypeInfo)]
575pub struct AvailabilityBitfield(pub BitVec<u8, bitvec::order::Lsb0>);
576
577impl From<BitVec<u8, bitvec::order::Lsb0>> for AvailabilityBitfield {
578 fn from(inner: BitVec<u8, bitvec::order::Lsb0>) -> Self {
579 AvailabilityBitfield(inner)
580 }
581}
582
583pub type SignedStatement = Signed<CompactStatement>;
585pub type UncheckedSignedStatement = UncheckedSigned<CompactStatement>;
587
588pub type SignedAvailabilityBitfield = Signed<AvailabilityBitfield>;
590pub type UncheckedSignedAvailabilityBitfield = UncheckedSigned<AvailabilityBitfield>;
592
593pub type SignedAvailabilityBitfields = Vec<SignedAvailabilityBitfield>;
595pub type UncheckedSignedAvailabilityBitfields = Vec<UncheckedSignedAvailabilityBitfield>;
598
599pub fn check_candidate_backing<H: AsRef<[u8]> + Clone + Encode + core::fmt::Debug>(
610 candidate_hash: CandidateHash,
611 validity_votes: &[ValidityAttestation],
612 validator_indices: &BitSlice<u8, bitvec::order::Lsb0>,
613 signing_context: &SigningContext<H>,
614 group_len: usize,
615 validator_lookup: impl Fn(usize) -> Option<ValidatorId>,
616) -> Result<usize, ()> {
617 if validator_indices.len() != group_len {
618 log::debug!(
619 target: LOG_TARGET,
620 "Check candidate backing: indices mismatch: group_len = {} , indices_len = {}",
621 group_len,
622 validator_indices.len(),
623 );
624 return Err(())
625 }
626
627 if validity_votes.len() > group_len {
628 log::debug!(
629 target: LOG_TARGET,
630 "Check candidate backing: Too many votes, expected: {}, found: {}",
631 group_len,
632 validity_votes.len(),
633 );
634 return Err(())
635 }
636
637 let mut signed = 0;
638 for ((val_in_group_idx, _), attestation) in validator_indices
639 .iter()
640 .enumerate()
641 .filter(|(_, signed)| **signed)
642 .zip(validity_votes.iter())
643 {
644 let validator_id = validator_lookup(val_in_group_idx).ok_or(())?;
645 let payload = attestation.signed_payload(candidate_hash, signing_context);
646 let sig = attestation.signature();
647
648 if sig.verify(&payload[..], &validator_id) {
649 signed += 1;
650 } else {
651 log::debug!(
652 target: LOG_TARGET,
653 "Check candidate backing: Invalid signature. validator_id = {:?}, validator_index = {} ",
654 validator_id,
655 val_in_group_idx,
656 );
657 return Err(())
658 }
659 }
660
661 if signed != validity_votes.len() {
662 log::error!(
663 target: LOG_TARGET,
664 "Check candidate backing: Too many signatures, expected = {}, found = {}",
665 validity_votes.len(),
666 signed,
667 );
668 return Err(())
669 }
670
671 Ok(signed)
672}
673
674#[derive(
676 Encode,
677 Decode,
678 DecodeWithMemTracking,
679 Default,
680 PartialOrd,
681 Ord,
682 Eq,
683 PartialEq,
684 Clone,
685 Copy,
686 TypeInfo,
687 RuntimeDebug,
688)]
689#[cfg_attr(feature = "std", derive(Hash))]
690pub struct CoreIndex(pub u32);
691
692impl From<u32> for CoreIndex {
693 fn from(i: u32) -> CoreIndex {
694 CoreIndex(i)
695 }
696}
697
698impl TypeIndex for CoreIndex {
699 fn type_index(&self) -> usize {
700 self.0 as usize
701 }
702}
703
704#[derive(
706 Encode,
707 Decode,
708 DecodeWithMemTracking,
709 Default,
710 Clone,
711 Copy,
712 Debug,
713 PartialEq,
714 Eq,
715 TypeInfo,
716 PartialOrd,
717 Ord,
718)]
719#[cfg_attr(feature = "std", derive(Hash))]
720pub struct GroupIndex(pub u32);
721
722impl From<u32> for GroupIndex {
723 fn from(i: u32) -> GroupIndex {
724 GroupIndex(i)
725 }
726}
727
728impl TypeIndex for GroupIndex {
729 fn type_index(&self) -> usize {
730 self.0 as usize
731 }
732}
733
734#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
736pub struct ParathreadClaim(pub Id, pub Option<CollatorId>);
737
738#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
740pub struct ParathreadEntry {
741 pub claim: ParathreadClaim,
743 pub retries: u32,
745}
746
747#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
749#[cfg_attr(feature = "std", derive(PartialEq))]
750pub struct GroupRotationInfo<N = BlockNumber> {
751 pub session_start_block: N,
753 pub group_rotation_frequency: N,
755 pub now: N,
757}
758
759impl GroupRotationInfo {
760 pub fn group_for_core(&self, core_index: CoreIndex, cores: usize) -> GroupIndex {
765 if self.group_rotation_frequency == 0 {
766 return GroupIndex(core_index.0)
767 }
768 if cores == 0 {
769 return GroupIndex(0)
770 }
771
772 let cores = core::cmp::min(cores, u32::MAX as usize);
773 let blocks_since_start = self.now.saturating_sub(self.session_start_block);
774 let rotations = blocks_since_start / self.group_rotation_frequency;
775
776 let idx = (core_index.0 as usize + rotations as usize) % cores;
779 GroupIndex(idx as u32)
780 }
781
782 pub fn core_for_group(&self, group_index: GroupIndex, cores: usize) -> CoreIndex {
787 if self.group_rotation_frequency == 0 {
788 return CoreIndex(group_index.0)
789 }
790 if cores == 0 {
791 return CoreIndex(0)
792 }
793
794 let cores = core::cmp::min(cores, u32::MAX as usize);
795 let blocks_since_start = self.now.saturating_sub(self.session_start_block);
796 let rotations = blocks_since_start / self.group_rotation_frequency;
797 let rotations = rotations % cores as u32;
798
799 let idx = (group_index.0 as usize + cores - rotations as usize) % cores;
805 CoreIndex(idx as u32)
806 }
807
808 pub fn bump_rotation(&self) -> Self {
810 GroupRotationInfo {
811 session_start_block: self.session_start_block,
812 group_rotation_frequency: self.group_rotation_frequency,
813 now: self.next_rotation_at(),
814 }
815 }
816}
817
818impl<N: Saturating + BaseArithmetic + Copy> GroupRotationInfo<N> {
819 pub fn next_rotation_at(&self) -> N {
822 let cycle_once = self.now + self.group_rotation_frequency;
823 cycle_once -
824 (cycle_once.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
825 }
826
827 pub fn last_rotation_at(&self) -> N {
830 self.now -
831 (self.now.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
832 }
833}
834
835#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
837#[cfg_attr(feature = "std", derive(PartialEq))]
838pub struct ScheduledCore {
839 pub para_id: Id,
841 pub collator: Option<CollatorId>,
845}
846
847#[derive(Clone, Copy, Encode, Decode, TypeInfo, RuntimeDebug)]
849#[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash))]
850pub enum OccupiedCoreAssumption {
851 #[codec(index = 0)]
853 Included,
854 #[codec(index = 1)]
856 TimedOut,
857 #[codec(index = 2)]
859 Free,
860}
861
862#[derive(Clone, RuntimeDebug)]
864pub struct ApprovalVote(pub CandidateHash);
865
866impl ApprovalVote {
867 pub fn signing_payload(&self, session_index: SessionIndex) -> Vec<u8> {
869 const MAGIC: [u8; 4] = *b"APPR";
870
871 (MAGIC, &self.0, session_index).encode()
872 }
873}
874
875#[derive(Clone, RuntimeDebug)]
877pub struct ApprovalVoteMultipleCandidates<'a>(pub &'a [CandidateHash]);
878
879impl<'a> ApprovalVoteMultipleCandidates<'a> {
880 pub fn signing_payload(&self, session_index: SessionIndex) -> Vec<u8> {
882 const MAGIC: [u8; 4] = *b"APPR";
883 if self.0.len() == 1 {
888 (MAGIC, self.0.first().expect("QED: we just checked"), session_index).encode()
889 } else {
890 (MAGIC, &self.0, session_index).encode()
891 }
892 }
893}
894
895#[derive(
897 RuntimeDebug,
898 Copy,
899 Clone,
900 PartialEq,
901 Encode,
902 Decode,
903 DecodeWithMemTracking,
904 TypeInfo,
905 serde::Serialize,
906 serde::Deserialize,
907)]
908pub struct ApprovalVotingParams {
909 pub max_approval_coalesce_count: u32,
914}
915
916impl Default for ApprovalVotingParams {
917 fn default() -> Self {
918 Self { max_approval_coalesce_count: 1 }
919 }
920}
921
922#[repr(u8)]
924pub enum ValidityError {
925 InvalidEthereumSignature = 0,
927 SignerHasNoClaim = 1,
929 NoPermission = 2,
931 InvalidStatement = 3,
933}
934
935impl From<ValidityError> for u8 {
936 fn from(err: ValidityError) -> Self {
937 err as u8
938 }
939}
940
941#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
944#[cfg_attr(feature = "std", derive(PartialEq))]
945pub struct AbridgedHostConfiguration {
946 pub max_code_size: u32,
948 pub max_head_data_size: u32,
950 pub max_upward_queue_count: u32,
952 pub max_upward_queue_size: u32,
956 pub max_upward_message_size: u32,
960 pub max_upward_message_num_per_candidate: u32,
964 pub hrmp_max_message_num_per_candidate: u32,
968 pub validation_upgrade_cooldown: BlockNumber,
970 pub validation_upgrade_delay: BlockNumber,
972 pub async_backing_params: AsyncBackingParams,
974}
975
976#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
979#[cfg_attr(feature = "std", derive(Default, PartialEq))]
980pub struct AbridgedHrmpChannel {
981 pub max_capacity: u32,
983 pub max_total_size: u32,
985 pub max_message_size: u32,
987 pub msg_count: u32,
990 pub total_size: u32,
993 pub mqc_head: Option<Hash>,
1001}
1002
1003#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
1005pub enum UpgradeRestriction {
1006 #[codec(index = 0)]
1009 Present,
1010}
1011
1012#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
1018pub enum UpgradeGoAhead {
1019 #[codec(index = 0)]
1028 Abort,
1029 #[codec(index = 1)]
1033 GoAhead,
1034}
1035
1036pub const POLKADOT_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"POL1";
1038
1039#[derive(Decode, Encode, Clone, PartialEq, Eq)]
1041pub enum ConsensusLog {
1042 #[codec(index = 1)]
1044 ParaUpgradeCode(Id, ValidationCodeHash),
1045 #[codec(index = 2)]
1047 ParaScheduleUpgradeCode(Id, ValidationCodeHash, BlockNumber),
1048 #[codec(index = 3)]
1051 ForceApprove(BlockNumber),
1052 #[codec(index = 4)]
1061 Revert(BlockNumber),
1062}
1063
1064impl ConsensusLog {
1065 pub fn from_digest_item(
1067 digest_item: &sp_runtime::DigestItem,
1068 ) -> Result<Option<Self>, codec::Error> {
1069 match digest_item {
1070 sp_runtime::DigestItem::Consensus(id, encoded) if id == &POLKADOT_ENGINE_ID =>
1071 Ok(Some(Self::decode(&mut &encoded[..])?)),
1072 _ => Ok(None),
1073 }
1074 }
1075}
1076
1077impl From<ConsensusLog> for sp_runtime::DigestItem {
1078 fn from(c: ConsensusLog) -> sp_runtime::DigestItem {
1079 Self::Consensus(POLKADOT_ENGINE_ID, c.encode())
1080 }
1081}
1082
1083#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1087pub enum DisputeStatement {
1088 #[codec(index = 0)]
1090 Valid(ValidDisputeStatementKind),
1091 #[codec(index = 1)]
1093 Invalid(InvalidDisputeStatementKind),
1094}
1095
1096impl DisputeStatement {
1097 pub fn payload_data(
1102 &self,
1103 candidate_hash: CandidateHash,
1104 session: SessionIndex,
1105 ) -> Result<Vec<u8>, ()> {
1106 match self {
1107 DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) =>
1108 Ok(ExplicitDisputeStatement { valid: true, candidate_hash, session }
1109 .signing_payload()),
1110 DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded(
1111 inclusion_parent,
1112 )) => Ok(CompactStatement::Seconded(candidate_hash).signing_payload(&SigningContext {
1113 session_index: session,
1114 parent_hash: *inclusion_parent,
1115 })),
1116 DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent)) =>
1117 Ok(CompactStatement::Valid(candidate_hash).signing_payload(&SigningContext {
1118 session_index: session,
1119 parent_hash: *inclusion_parent,
1120 })),
1121 DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) =>
1122 Ok(ApprovalVote(candidate_hash).signing_payload(session)),
1123 DisputeStatement::Valid(
1124 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes),
1125 ) =>
1126 if candidate_hashes.contains(&candidate_hash) {
1127 Ok(ApprovalVoteMultipleCandidates(candidate_hashes).signing_payload(session))
1128 } else {
1129 Err(())
1130 },
1131 DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit) =>
1132 Ok(ExplicitDisputeStatement { valid: false, candidate_hash, session }
1133 .signing_payload()),
1134 }
1135 }
1136
1137 pub fn check_signature(
1139 &self,
1140 validator_public: &ValidatorId,
1141 candidate_hash: CandidateHash,
1142 session: SessionIndex,
1143 validator_signature: &ValidatorSignature,
1144 ) -> Result<(), ()> {
1145 let payload = self.payload_data(candidate_hash, session)?;
1146
1147 if validator_signature.verify(&payload[..], &validator_public) {
1148 Ok(())
1149 } else {
1150 Err(())
1151 }
1152 }
1153
1154 pub fn indicates_validity(&self) -> bool {
1156 match *self {
1157 DisputeStatement::Valid(_) => true,
1158 DisputeStatement::Invalid(_) => false,
1159 }
1160 }
1161
1162 pub fn indicates_invalidity(&self) -> bool {
1164 match *self {
1165 DisputeStatement::Valid(_) => false,
1166 DisputeStatement::Invalid(_) => true,
1167 }
1168 }
1169
1170 pub fn is_backing(&self) -> bool {
1172 match self {
1173 Self::Valid(s) => s.is_backing(),
1174 Self::Invalid(_) => false,
1175 }
1176 }
1177}
1178
1179#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1181pub enum ValidDisputeStatementKind {
1182 #[codec(index = 0)]
1184 Explicit,
1185 #[codec(index = 1)]
1187 BackingSeconded(Hash),
1188 #[codec(index = 2)]
1190 BackingValid(Hash),
1191 #[codec(index = 3)]
1193 ApprovalChecking,
1194 #[codec(index = 4)]
1199 ApprovalCheckingMultipleCandidates(Vec<CandidateHash>),
1200}
1201
1202impl ValidDisputeStatementKind {
1203 pub fn is_backing(&self) -> bool {
1205 match self {
1206 ValidDisputeStatementKind::BackingSeconded(_) |
1207 ValidDisputeStatementKind::BackingValid(_) => true,
1208 ValidDisputeStatementKind::Explicit |
1209 ValidDisputeStatementKind::ApprovalChecking |
1210 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(_) => false,
1211 }
1212 }
1213}
1214
1215#[derive(Encode, Decode, DecodeWithMemTracking, Copy, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1217pub enum InvalidDisputeStatementKind {
1218 #[codec(index = 0)]
1220 Explicit,
1221}
1222
1223#[derive(Clone, PartialEq, RuntimeDebug)]
1225pub struct ExplicitDisputeStatement {
1226 pub valid: bool,
1228 pub candidate_hash: CandidateHash,
1230 pub session: SessionIndex,
1232}
1233
1234impl ExplicitDisputeStatement {
1235 pub fn signing_payload(&self) -> Vec<u8> {
1237 const MAGIC: [u8; 4] = *b"DISP";
1238
1239 (MAGIC, self.valid, self.candidate_hash, self.session).encode()
1240 }
1241}
1242
1243#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1245pub struct DisputeStatementSet {
1246 pub candidate_hash: CandidateHash,
1248 pub session: SessionIndex,
1250 pub statements: Vec<(DisputeStatement, ValidatorIndex, ValidatorSignature)>,
1252}
1253
1254impl From<CheckedDisputeStatementSet> for DisputeStatementSet {
1255 fn from(other: CheckedDisputeStatementSet) -> Self {
1256 other.0
1257 }
1258}
1259
1260impl AsRef<DisputeStatementSet> for DisputeStatementSet {
1261 fn as_ref(&self) -> &DisputeStatementSet {
1262 &self
1263 }
1264}
1265
1266pub type MultiDisputeStatementSet = Vec<DisputeStatementSet>;
1268
1269#[derive(Clone, PartialEq, RuntimeDebug, Encode)]
1271pub struct CheckedDisputeStatementSet(DisputeStatementSet);
1272
1273impl AsRef<DisputeStatementSet> for CheckedDisputeStatementSet {
1274 fn as_ref(&self) -> &DisputeStatementSet {
1275 &self.0
1276 }
1277}
1278
1279impl core::cmp::PartialEq<DisputeStatementSet> for CheckedDisputeStatementSet {
1280 fn eq(&self, other: &DisputeStatementSet) -> bool {
1281 self.0.eq(other)
1282 }
1283}
1284
1285impl CheckedDisputeStatementSet {
1286 pub fn unchecked_from_unchecked(unchecked: DisputeStatementSet) -> Self {
1289 Self(unchecked)
1290 }
1291}
1292
1293pub type CheckedMultiDisputeStatementSet = Vec<CheckedDisputeStatementSet>;
1295
1296#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, TypeInfo)]
1298pub struct DisputeState<N = BlockNumber> {
1299 pub validators_for: BitVec<u8, bitvec::order::Lsb0>, pub validators_against: BitVec<u8, bitvec::order::Lsb0>, pub start: N,
1305 pub concluded_at: Option<N>,
1307}
1308
1309#[derive(Clone, Eq, PartialEq, Decode, DecodeWithMemTracking, Encode, RuntimeDebug, TypeInfo)]
1312pub enum ValidityAttestation {
1313 #[codec(index = 1)]
1316 Implicit(ValidatorSignature),
1317 #[codec(index = 2)]
1320 Explicit(ValidatorSignature),
1321}
1322
1323impl ValidityAttestation {
1324 pub fn to_compact_statement(&self, candidate_hash: CandidateHash) -> CompactStatement {
1327 match *self {
1331 ValidityAttestation::Implicit(_) => CompactStatement::Seconded(candidate_hash),
1332 ValidityAttestation::Explicit(_) => CompactStatement::Valid(candidate_hash),
1333 }
1334 }
1335
1336 pub fn signature(&self) -> &ValidatorSignature {
1338 match *self {
1339 ValidityAttestation::Implicit(ref sig) => sig,
1340 ValidityAttestation::Explicit(ref sig) => sig,
1341 }
1342 }
1343
1344 pub fn signed_payload<H: Encode>(
1347 &self,
1348 candidate_hash: CandidateHash,
1349 signing_context: &SigningContext<H>,
1350 ) -> Vec<u8> {
1351 match *self {
1352 ValidityAttestation::Implicit(_) =>
1353 (CompactStatement::Seconded(candidate_hash), signing_context).encode(),
1354 ValidityAttestation::Explicit(_) =>
1355 (CompactStatement::Valid(candidate_hash), signing_context).encode(),
1356 }
1357 }
1358}
1359
1360#[derive(Clone, Eq, PartialEq, Default, Decode, Encode, RuntimeDebug)]
1362pub struct SigningContext<H = Hash> {
1363 pub session_index: sp_staking::SessionIndex,
1365 pub parent_hash: H,
1367}
1368
1369const BACKING_STATEMENT_MAGIC: [u8; 4] = *b"BKNG";
1370
1371#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
1374#[cfg_attr(feature = "std", derive(Hash))]
1375pub enum CompactStatement {
1376 Seconded(CandidateHash),
1378 Valid(CandidateHash),
1380}
1381
1382impl CompactStatement {
1383 pub fn signing_payload(&self, context: &SigningContext) -> Vec<u8> {
1386 (self, context).encode()
1387 }
1388
1389 pub fn candidate_hash(&self) -> &CandidateHash {
1391 match *self {
1392 CompactStatement::Seconded(ref h) | CompactStatement::Valid(ref h) => h,
1393 }
1394 }
1395}
1396
1397#[derive(Encode, Decode, TypeInfo)]
1399enum CompactStatementInner {
1400 #[codec(index = 1)]
1401 Seconded(CandidateHash),
1402 #[codec(index = 2)]
1403 Valid(CandidateHash),
1404}
1405
1406impl From<CompactStatement> for CompactStatementInner {
1407 fn from(s: CompactStatement) -> Self {
1408 match s {
1409 CompactStatement::Seconded(h) => CompactStatementInner::Seconded(h),
1410 CompactStatement::Valid(h) => CompactStatementInner::Valid(h),
1411 }
1412 }
1413}
1414
1415impl codec::Encode for CompactStatement {
1416 fn size_hint(&self) -> usize {
1417 4 + 1 + 32
1419 }
1420
1421 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
1422 dest.write(&BACKING_STATEMENT_MAGIC);
1423 CompactStatementInner::from(self.clone()).encode_to(dest)
1424 }
1425}
1426
1427impl codec::Decode for CompactStatement {
1428 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
1429 let maybe_magic = <[u8; 4]>::decode(input)?;
1430 if maybe_magic != BACKING_STATEMENT_MAGIC {
1431 return Err(codec::Error::from("invalid magic string"))
1432 }
1433
1434 Ok(match CompactStatementInner::decode(input)? {
1435 CompactStatementInner::Seconded(h) => CompactStatement::Seconded(h),
1436 CompactStatementInner::Valid(h) => CompactStatement::Valid(h),
1437 })
1438 }
1439}
1440
1441#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1443#[cfg_attr(feature = "std", derive(PartialEq))]
1444pub struct IndexedVec<K, V>(Vec<V>, PhantomData<fn(K) -> K>);
1445
1446impl<K, V> Default for IndexedVec<K, V> {
1447 fn default() -> Self {
1448 Self(vec![], PhantomData)
1449 }
1450}
1451
1452impl<K, V> From<Vec<V>> for IndexedVec<K, V> {
1453 fn from(validators: Vec<V>) -> Self {
1454 Self(validators, PhantomData)
1455 }
1456}
1457
1458impl<K, V> FromIterator<V> for IndexedVec<K, V> {
1459 fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
1460 Self(Vec::from_iter(iter), PhantomData)
1461 }
1462}
1463
1464impl<K, V> IndexedVec<K, V>
1465where
1466 V: Clone,
1467{
1468 pub fn get(&self, index: K) -> Option<&V>
1470 where
1471 K: TypeIndex,
1472 {
1473 self.0.get(index.type_index())
1474 }
1475
1476 pub fn get_mut(&mut self, index: K) -> Option<&mut V>
1478 where
1479 K: TypeIndex,
1480 {
1481 self.0.get_mut(index.type_index())
1482 }
1483
1484 pub fn len(&self) -> usize {
1486 self.0.len()
1487 }
1488
1489 pub fn to_vec(&self) -> Vec<V> {
1491 self.0.clone()
1492 }
1493
1494 pub fn iter(&self) -> Iter<'_, V> {
1496 self.0.iter()
1497 }
1498
1499 pub fn iter_mut(&mut self) -> IterMut<'_, V> {
1501 self.0.iter_mut()
1502 }
1503
1504 pub fn into_iter(self) -> IntoIter<V> {
1506 self.0.into_iter()
1507 }
1508
1509 pub fn is_empty(&self) -> bool {
1511 self.0.is_empty()
1512 }
1513}
1514
1515pub const fn byzantine_threshold(n: usize) -> usize {
1519 n.saturating_sub(1) / 3
1520}
1521
1522pub const fn supermajority_threshold(n: usize) -> usize {
1525 n - byzantine_threshold(n)
1526}
1527
1528pub fn effective_minimum_backing_votes(
1530 group_len: usize,
1531 configured_minimum_backing_votes: u32,
1532) -> usize {
1533 core::cmp::min(group_len, configured_minimum_backing_votes as usize)
1534}
1535
1536#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1541#[cfg_attr(feature = "std", derive(PartialEq))]
1542pub struct SessionInfo {
1543 pub active_validator_indices: Vec<ValidatorIndex>,
1547 pub random_seed: [u8; 32],
1549 pub dispute_period: SessionIndex,
1551
1552 pub validators: IndexedVec<ValidatorIndex, ValidatorId>,
1561 pub discovery_keys: Vec<AuthorityDiscoveryId>,
1568 pub assignment_keys: Vec<AssignmentId>,
1579 pub validator_groups: IndexedVec<GroupIndex, Vec<ValidatorIndex>>,
1583 pub n_cores: u32,
1585 pub zeroth_delay_tranche_width: u32,
1587 pub relay_vrf_modulo_samples: u32,
1589 pub n_delay_tranches: u32,
1591 pub no_show_slots: u32,
1594 pub needed_approvals: u32,
1596}
1597
1598#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1601pub struct PvfCheckStatement {
1602 pub accept: bool,
1604 pub subject: ValidationCodeHash,
1606 pub session_index: SessionIndex,
1608 pub validator_index: ValidatorIndex,
1610}
1611
1612impl PvfCheckStatement {
1613 pub fn signing_payload(&self) -> Vec<u8> {
1618 const MAGIC: [u8; 4] = *b"VCPC"; (MAGIC, self.accept, self.subject, self.session_index, self.validator_index).encode()
1620 }
1621}
1622
1623pub struct WellKnownKey<T> {
1627 pub key: Vec<u8>,
1629 _p: core::marker::PhantomData<T>,
1630}
1631
1632impl<T> From<Vec<u8>> for WellKnownKey<T> {
1633 fn from(key: Vec<u8>) -> Self {
1634 Self { key, _p: Default::default() }
1635 }
1636}
1637
1638impl<T> AsRef<[u8]> for WellKnownKey<T> {
1639 fn as_ref(&self) -> &[u8] {
1640 self.key.as_ref()
1641 }
1642}
1643
1644impl<T: Decode> WellKnownKey<T> {
1645 pub fn get(&self) -> Option<T> {
1647 sp_io::storage::get(&self.key)
1648 .and_then(|raw| codec::DecodeAll::decode_all(&mut raw.as_ref()).ok())
1649 }
1650}
1651
1652impl<T: Encode> WellKnownKey<T> {
1653 pub fn set(&self, value: T) {
1655 sp_io::storage::set(&self.key, &value.encode());
1656 }
1657}
1658
1659#[derive(
1661 Encode,
1662 Decode,
1663 DecodeWithMemTracking,
1664 TypeInfo,
1665 Clone,
1666 Copy,
1667 Debug,
1668 PartialEq,
1669 Eq,
1670 Serialize,
1671 Deserialize,
1672)]
1673pub enum PvfPrepKind {
1674 Precheck,
1676
1677 Prepare,
1679}
1680
1681#[derive(
1683 Encode,
1684 Decode,
1685 DecodeWithMemTracking,
1686 TypeInfo,
1687 Clone,
1688 Copy,
1689 Debug,
1690 PartialEq,
1691 Eq,
1692 Serialize,
1693 Deserialize,
1694)]
1695pub enum PvfExecKind {
1696 Backing,
1698 Approval,
1700}
1701
1702pub type NodeFeatures = BitVec<u8, bitvec::order::Lsb0>;
1704
1705pub mod node_features {
1707 #[repr(u8)]
1710 #[derive(Clone, Copy)]
1711 pub enum FeatureIndex {
1712 EnableAssignmentsV2 = 0,
1715 ElasticScalingMVP = 1,
1719 AvailabilityChunkMapping = 2,
1725 CandidateReceiptV2 = 3,
1729 FirstUnassigned = 4,
1733 }
1734}
1735
1736#[derive(
1738 RuntimeDebug,
1739 Copy,
1740 Clone,
1741 PartialEq,
1742 Encode,
1743 Decode,
1744 DecodeWithMemTracking,
1745 TypeInfo,
1746 serde::Serialize,
1747 serde::Deserialize,
1748)]
1749pub struct SchedulerParams<BlockNumber> {
1750 pub group_rotation_frequency: BlockNumber,
1754 pub paras_availability_period: BlockNumber,
1769 pub max_validators_per_core: Option<u32>,
1773 pub lookahead: u32,
1775 pub num_cores: u32,
1777 #[deprecated]
1780 pub max_availability_timeouts: u32,
1781 pub on_demand_queue_max_size: u32,
1783 pub on_demand_target_queue_utilization: Perbill,
1785 pub on_demand_fee_variability: Perbill,
1788 pub on_demand_base_fee: Balance,
1790 #[deprecated]
1793 pub ttl: BlockNumber,
1794}
1795
1796impl<BlockNumber: Default + From<u32>> Default for SchedulerParams<BlockNumber> {
1797 #[allow(deprecated)]
1798 fn default() -> Self {
1799 Self {
1800 group_rotation_frequency: 1u32.into(),
1801 paras_availability_period: 1u32.into(),
1802 max_validators_per_core: Default::default(),
1803 lookahead: 1,
1804 num_cores: Default::default(),
1805 max_availability_timeouts: Default::default(),
1806 on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE,
1807 on_demand_target_queue_utilization: Perbill::from_percent(25),
1808 on_demand_fee_variability: Perbill::from_percent(3),
1809 on_demand_base_fee: 10_000_000u128,
1810 ttl: 5u32.into(),
1811 }
1812 }
1813}
1814
1815#[derive(
1817 PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, Clone, TypeInfo, RuntimeDebug, Copy,
1818)]
1819pub struct InternalVersion(pub u8);
1820
1821#[derive(PartialEq, Eq, Clone, TypeInfo, RuntimeDebug)]
1823pub enum CandidateDescriptorVersion {
1824 V1,
1826 V2,
1828 Unknown,
1830}
1831
1832#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
1834pub struct CandidateDescriptorV2<H = Hash> {
1835 pub(super) para_id: ParaId,
1837 relay_parent: H,
1839 pub(super) version: InternalVersion,
1844 pub(super) core_index: u16,
1846 session_index: SessionIndex,
1848 reserved1: [u8; 25],
1850 persisted_validation_data_hash: Hash,
1854 pov_hash: Hash,
1856 erasure_root: Hash,
1858 reserved2: [u8; 64],
1860 para_head: Hash,
1862 validation_code_hash: ValidationCodeHash,
1864}
1865
1866impl<H> CandidateDescriptorV2<H> {
1867 pub fn version(&self) -> CandidateDescriptorVersion {
1872 if self.reserved2 != [0u8; 64] || self.reserved1 != [0u8; 25] {
1873 return CandidateDescriptorVersion::V1
1874 }
1875
1876 match self.version.0 {
1877 0 => CandidateDescriptorVersion::V2,
1878 _ => CandidateDescriptorVersion::Unknown,
1879 }
1880 }
1881}
1882
1883macro_rules! impl_getter {
1884 ($field:ident, $type:ident) => {
1885 pub fn $field(&self) -> $type {
1887 self.$field
1888 }
1889 };
1890}
1891
1892impl<H: Copy> CandidateDescriptorV2<H> {
1893 impl_getter!(erasure_root, Hash);
1894 impl_getter!(para_head, Hash);
1895 impl_getter!(relay_parent, H);
1896 impl_getter!(para_id, ParaId);
1897 impl_getter!(persisted_validation_data_hash, Hash);
1898 impl_getter!(pov_hash, Hash);
1899 impl_getter!(validation_code_hash, ValidationCodeHash);
1900
1901 fn rebuild_collator_field(&self) -> CollatorId {
1902 let mut collator_id = Vec::with_capacity(32);
1903 let core_index: [u8; 2] = self.core_index.to_ne_bytes();
1904 let session_index: [u8; 4] = self.session_index.to_ne_bytes();
1905
1906 collator_id.push(self.version.0);
1907 collator_id.extend_from_slice(core_index.as_slice());
1908 collator_id.extend_from_slice(session_index.as_slice());
1909 collator_id.extend_from_slice(self.reserved1.as_slice());
1910
1911 CollatorId::from_slice(&collator_id.as_slice())
1912 .expect("Slice size is exactly 32 bytes; qed")
1913 }
1914
1915 #[cfg(feature = "test")]
1916 #[doc(hidden)]
1917 pub fn rebuild_collator_field_for_tests(&self) -> CollatorId {
1918 self.rebuild_collator_field()
1919 }
1920
1921 pub fn collator(&self) -> Option<CollatorId> {
1923 if self.version() == CandidateDescriptorVersion::V1 {
1924 Some(self.rebuild_collator_field())
1925 } else {
1926 None
1927 }
1928 }
1929
1930 fn rebuild_signature_field(&self) -> CollatorSignature {
1931 CollatorSignature::from_slice(self.reserved2.as_slice())
1932 .expect("Slice size is exactly 64 bytes; qed")
1933 }
1934
1935 #[cfg(feature = "test")]
1936 #[doc(hidden)]
1937 pub fn rebuild_signature_field_for_tests(&self) -> CollatorSignature {
1938 self.rebuild_signature_field()
1939 }
1940
1941 pub fn signature(&self) -> Option<CollatorSignature> {
1943 if self.version() == CandidateDescriptorVersion::V1 {
1944 return Some(self.rebuild_signature_field())
1945 }
1946
1947 None
1948 }
1949
1950 pub fn core_index(&self) -> Option<CoreIndex> {
1952 if self.version() == CandidateDescriptorVersion::V1 {
1953 return None
1954 }
1955
1956 Some(CoreIndex(self.core_index as u32))
1957 }
1958
1959 pub fn session_index(&self) -> Option<SessionIndex> {
1961 if self.version() == CandidateDescriptorVersion::V1 {
1962 return None
1963 }
1964
1965 Some(self.session_index)
1966 }
1967}
1968
1969impl<H> core::fmt::Debug for CandidateDescriptorV2<H>
1970where
1971 H: core::fmt::Debug,
1972{
1973 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1974 match self.version() {
1975 CandidateDescriptorVersion::V1 => f
1976 .debug_struct("CandidateDescriptorV1")
1977 .field("para_id", &self.para_id)
1978 .field("relay_parent", &self.relay_parent)
1979 .field("persisted_validation_hash", &self.persisted_validation_data_hash)
1980 .field("pov_hash", &self.pov_hash)
1981 .field("erasure_root", &self.erasure_root)
1982 .field("para_head", &self.para_head)
1983 .field("validation_code_hash", &self.validation_code_hash)
1984 .finish(),
1985 CandidateDescriptorVersion::V2 => f
1986 .debug_struct("CandidateDescriptorV2")
1987 .field("para_id", &self.para_id)
1988 .field("relay_parent", &self.relay_parent)
1989 .field("core_index", &self.core_index)
1990 .field("session_index", &self.session_index)
1991 .field("persisted_validation_data_hash", &self.persisted_validation_data_hash)
1992 .field("pov_hash", &self.pov_hash)
1993 .field("erasure_root", &self.pov_hash)
1994 .field("para_head", &self.para_head)
1995 .field("validation_code_hash", &self.validation_code_hash)
1996 .finish(),
1997 CandidateDescriptorVersion::Unknown => {
1998 write!(f, "Invalid CandidateDescriptorVersion")
1999 },
2000 }
2001 }
2002}
2003
2004impl<H: Copy + AsRef<[u8]>> CandidateDescriptorV2<H> {
2005 pub fn new(
2007 para_id: Id,
2008 relay_parent: H,
2009 core_index: CoreIndex,
2010 session_index: SessionIndex,
2011 persisted_validation_data_hash: Hash,
2012 pov_hash: Hash,
2013 erasure_root: Hash,
2014 para_head: Hash,
2015 validation_code_hash: ValidationCodeHash,
2016 ) -> Self {
2017 Self {
2018 para_id,
2019 relay_parent,
2020 version: InternalVersion(0),
2021 core_index: core_index.0 as u16,
2022 session_index,
2023 reserved1: [0; 25],
2024 persisted_validation_data_hash,
2025 pov_hash,
2026 erasure_root,
2027 reserved2: [0; 64],
2028 para_head,
2029 validation_code_hash,
2030 }
2031 }
2032
2033 #[cfg(feature = "test")]
2034 #[doc(hidden)]
2035 pub fn new_from_raw(
2036 para_id: Id,
2037 relay_parent: H,
2038 version: InternalVersion,
2039 core_index: u16,
2040 session_index: SessionIndex,
2041 reserved1: [u8; 25],
2042 persisted_validation_data_hash: Hash,
2043 pov_hash: Hash,
2044 erasure_root: Hash,
2045 reserved2: [u8; 64],
2046 para_head: Hash,
2047 validation_code_hash: ValidationCodeHash,
2048 ) -> Self {
2049 Self {
2050 para_id,
2051 relay_parent,
2052 version,
2053 core_index,
2054 session_index,
2055 reserved1,
2056 persisted_validation_data_hash,
2057 pov_hash,
2058 erasure_root,
2059 reserved2,
2060 para_head,
2061 validation_code_hash,
2062 }
2063 }
2064}
2065
2066#[cfg(feature = "test")]
2068pub trait MutateDescriptorV2<H> {
2069 fn set_relay_parent(&mut self, relay_parent: H);
2071 fn set_para_id(&mut self, para_id: Id);
2073 fn set_pov_hash(&mut self, pov_hash: Hash);
2075 fn set_version(&mut self, version: InternalVersion);
2077 fn set_persisted_validation_data_hash(&mut self, persisted_validation_data_hash: Hash);
2079 fn set_validation_code_hash(&mut self, validation_code_hash: ValidationCodeHash);
2081 fn set_erasure_root(&mut self, erasure_root: Hash);
2083 fn set_para_head(&mut self, para_head: Hash);
2085 fn set_core_index(&mut self, core_index: CoreIndex);
2087 fn set_session_index(&mut self, session_index: SessionIndex);
2089 fn set_reserved2(&mut self, reserved2: [u8; 64]);
2091}
2092
2093#[cfg(feature = "test")]
2094impl<H> MutateDescriptorV2<H> for CandidateDescriptorV2<H> {
2095 fn set_para_id(&mut self, para_id: Id) {
2096 self.para_id = para_id;
2097 }
2098
2099 fn set_relay_parent(&mut self, relay_parent: H) {
2100 self.relay_parent = relay_parent;
2101 }
2102
2103 fn set_pov_hash(&mut self, pov_hash: Hash) {
2104 self.pov_hash = pov_hash;
2105 }
2106
2107 fn set_version(&mut self, version: InternalVersion) {
2108 self.version = version;
2109 }
2110
2111 fn set_core_index(&mut self, core_index: CoreIndex) {
2112 self.core_index = core_index.0 as u16;
2113 }
2114
2115 fn set_session_index(&mut self, session_index: SessionIndex) {
2116 self.session_index = session_index;
2117 }
2118
2119 fn set_persisted_validation_data_hash(&mut self, persisted_validation_data_hash: Hash) {
2120 self.persisted_validation_data_hash = persisted_validation_data_hash;
2121 }
2122
2123 fn set_validation_code_hash(&mut self, validation_code_hash: ValidationCodeHash) {
2124 self.validation_code_hash = validation_code_hash;
2125 }
2126
2127 fn set_erasure_root(&mut self, erasure_root: Hash) {
2128 self.erasure_root = erasure_root;
2129 }
2130
2131 fn set_para_head(&mut self, para_head: Hash) {
2132 self.para_head = para_head;
2133 }
2134
2135 fn set_reserved2(&mut self, reserved2: [u8; 64]) {
2136 self.reserved2 = reserved2;
2137 }
2138}
2139
2140#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
2142pub struct CandidateReceiptV2<H = Hash> {
2143 pub descriptor: CandidateDescriptorV2<H>,
2145 pub commitments_hash: Hash,
2147}
2148
2149#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
2151pub struct CommittedCandidateReceiptV2<H = Hash> {
2152 pub descriptor: CandidateDescriptorV2<H>,
2154 pub commitments: CandidateCommitments,
2156}
2157
2158#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
2160#[cfg_attr(feature = "std", derive(PartialEq))]
2161pub enum CandidateEvent<H = Hash> {
2162 #[codec(index = 0)]
2165 CandidateBacked(CandidateReceiptV2<H>, HeadData, CoreIndex, GroupIndex),
2166 #[codec(index = 1)]
2170 CandidateIncluded(CandidateReceiptV2<H>, HeadData, CoreIndex, GroupIndex),
2171 #[codec(index = 2)]
2174 CandidateTimedOut(CandidateReceiptV2<H>, HeadData, CoreIndex),
2175}
2176
2177impl<H> CandidateReceiptV2<H> {
2178 pub fn descriptor(&self) -> &CandidateDescriptorV2<H> {
2180 &self.descriptor
2181 }
2182
2183 pub fn hash(&self) -> CandidateHash
2185 where
2186 H: Encode,
2187 {
2188 CandidateHash(BlakeTwo256::hash_of(self))
2189 }
2190}
2191
2192impl<H: Clone> CommittedCandidateReceiptV2<H> {
2193 pub fn to_plain(&self) -> CandidateReceiptV2<H> {
2195 CandidateReceiptV2 {
2196 descriptor: self.descriptor.clone(),
2197 commitments_hash: self.commitments.hash(),
2198 }
2199 }
2200
2201 pub fn hash(&self) -> CandidateHash
2206 where
2207 H: Encode,
2208 {
2209 self.to_plain().hash()
2210 }
2211
2212 pub fn corresponds_to(&self, receipt: &CandidateReceiptV2<H>) -> bool
2214 where
2215 H: PartialEq,
2216 {
2217 receipt.descriptor == self.descriptor && receipt.commitments_hash == self.commitments.hash()
2218 }
2219}
2220
2221impl PartialOrd for CommittedCandidateReceiptV2 {
2222 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
2223 Some(self.cmp(other))
2224 }
2225}
2226
2227impl Ord for CommittedCandidateReceiptV2 {
2228 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
2229 self.descriptor
2230 .para_id
2231 .cmp(&other.descriptor.para_id)
2232 .then_with(|| self.commitments.head_data.cmp(&other.commitments.head_data))
2233 }
2234}
2235
2236#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Debug, Copy)]
2239pub struct CoreSelector(pub u8);
2240
2241#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Debug, Copy)]
2243pub struct ClaimQueueOffset(pub u8);
2244
2245#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Debug)]
2247pub enum UMPSignal {
2248 SelectCore(CoreSelector, ClaimQueueOffset),
2252 ApprovedPeer(ApprovedPeerId),
2254}
2255
2256pub const DEFAULT_CLAIM_QUEUE_OFFSET: u8 = 0;
2259
2260pub type ApprovedPeerId = BoundedVec<u8, ConstU32<64>>;
2264
2265#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug, Default)]
2266pub struct CandidateUMPSignals {
2268 pub(super) select_core: Option<(CoreSelector, ClaimQueueOffset)>,
2269 pub(super) approved_peer: Option<ApprovedPeerId>,
2270}
2271
2272impl CandidateUMPSignals {
2273 pub fn core_selector(&self) -> Option<(CoreSelector, ClaimQueueOffset)> {
2275 self.select_core
2276 }
2277
2278 pub fn approved_peer(&self) -> Option<&ApprovedPeerId> {
2280 self.approved_peer.as_ref()
2281 }
2282
2283 pub fn is_empty(&self) -> bool {
2285 self.select_core.is_none() && self.approved_peer.is_none()
2286 }
2287
2288 fn try_decode_signal(
2289 &mut self,
2290 buffer: &mut impl codec::Input,
2291 ) -> Result<(), CommittedCandidateReceiptError> {
2292 match UMPSignal::decode(buffer)
2293 .map_err(|_| CommittedCandidateReceiptError::UmpSignalDecode)?
2294 {
2295 UMPSignal::ApprovedPeer(approved_peer_id) if self.approved_peer.is_none() => {
2296 self.approved_peer = Some(approved_peer_id);
2297 },
2298 UMPSignal::SelectCore(core_selector, cq_offset) if self.select_core.is_none() => {
2299 self.select_core = Some((core_selector, cq_offset));
2300 },
2301 _ => {
2302 return Err(CommittedCandidateReceiptError::DuplicateUMPSignal)
2304 },
2305 };
2306
2307 Ok(())
2308 }
2309
2310 #[cfg(feature = "test")]
2311 #[doc(hidden)]
2312 pub fn dummy(
2313 select_core: Option<(CoreSelector, ClaimQueueOffset)>,
2314 approved_peer: Option<ApprovedPeerId>,
2315 ) -> Self {
2316 Self { select_core, approved_peer }
2317 }
2318}
2319
2320pub const UMP_SEPARATOR: Vec<u8> = vec![];
2322
2323pub fn skip_ump_signals<'a>(
2325 upward_messages: impl Iterator<Item = &'a Vec<u8>>,
2326) -> impl Iterator<Item = &'a Vec<u8>> {
2327 upward_messages.take_while(|message| *message != &UMP_SEPARATOR)
2328}
2329
2330impl CandidateCommitments {
2331 pub fn ump_signals(&self) -> Result<CandidateUMPSignals, CommittedCandidateReceiptError> {
2334 let mut res = CandidateUMPSignals::default();
2335
2336 let mut signals_iter =
2337 self.upward_messages.iter().skip_while(|message| *message != &UMP_SEPARATOR);
2338
2339 if signals_iter.next().is_none() {
2340 return Ok(res)
2342 }
2343
2344 let Some(first_signal) = signals_iter.next() else { return Ok(res) };
2346 res.try_decode_signal(&mut first_signal.as_slice())?;
2347
2348 let Some(second_signal) = signals_iter.next() else { return Ok(res) };
2350 res.try_decode_signal(&mut second_signal.as_slice())?;
2351
2352 if signals_iter.next().is_some() {
2354 return Err(CommittedCandidateReceiptError::TooManyUMPSignals)
2355 }
2356
2357 Ok(res)
2358 }
2359}
2360
2361#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
2363#[cfg_attr(feature = "std", derive(thiserror::Error))]
2364pub enum CommittedCandidateReceiptError {
2365 #[cfg_attr(feature = "std", error("The specified core index is invalid"))]
2367 InvalidCoreIndex,
2368 #[cfg_attr(
2370 feature = "std",
2371 error("The core index in commitments ({commitments:?}) doesn't match the one in descriptor ({descriptor:?})")
2372 )]
2373 CoreIndexMismatch {
2374 descriptor: CoreIndex,
2376 commitments: CoreIndex,
2378 },
2379 #[cfg_attr(feature = "std", error("The core selector or claim queue offset is invalid"))]
2381 InvalidSelectedCore,
2382 #[cfg_attr(feature = "std", error("Could not decode UMP signal"))]
2383 UmpSignalDecode,
2385 #[cfg_attr(
2387 feature = "std",
2388 error("The parachain is not assigned to any core at specified claim queue offset")
2389 )]
2390 NoAssignment,
2391 #[cfg_attr(feature = "std", error("Unknown internal version"))]
2393 UnknownVersion(InternalVersion),
2394 #[cfg_attr(feature = "std", error("Too many UMP signals"))]
2396 TooManyUMPSignals,
2397 #[cfg_attr(feature = "std", error("Duplicate UMP signal"))]
2399 DuplicateUMPSignal,
2400 #[cfg_attr(feature = "std", error("Version 1 receipt does not support ump signals"))]
2403 UMPSignalWithV1Decriptor,
2404}
2405
2406impl<H: Copy> CommittedCandidateReceiptV2<H> {
2407 pub fn parse_ump_signals(
2415 &self,
2416 cores_per_para: &TransposedClaimQueue,
2417 ) -> Result<CandidateUMPSignals, CommittedCandidateReceiptError> {
2418 let signals = self.commitments.ump_signals()?;
2419
2420 match self.descriptor.version() {
2421 CandidateDescriptorVersion::V1 => {
2422 if !signals.is_empty() {
2425 return Err(CommittedCandidateReceiptError::UMPSignalWithV1Decriptor)
2426 } else {
2427 return Ok(CandidateUMPSignals::default())
2429 }
2430 },
2431 CandidateDescriptorVersion::V2 => {},
2432 CandidateDescriptorVersion::Unknown =>
2433 return Err(CommittedCandidateReceiptError::UnknownVersion(self.descriptor.version)),
2434 }
2435
2436 let (maybe_core_index_selector, cq_offset) = signals
2438 .core_selector()
2439 .map(|(selector, offset)| (Some(selector), offset))
2440 .unwrap_or_else(|| (None, ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET)));
2441
2442 self.check_core_index(cores_per_para, maybe_core_index_selector, cq_offset)?;
2443
2444 Ok(signals)
2447 }
2448
2449 fn check_core_index(
2453 &self,
2454 cores_per_para: &TransposedClaimQueue,
2455 maybe_core_index_selector: Option<CoreSelector>,
2456 cq_offset: ClaimQueueOffset,
2457 ) -> Result<(), CommittedCandidateReceiptError> {
2458 let assigned_cores = cores_per_para
2459 .get(&self.descriptor.para_id())
2460 .ok_or(CommittedCandidateReceiptError::NoAssignment)?
2461 .get(&cq_offset.0)
2462 .ok_or(CommittedCandidateReceiptError::NoAssignment)?;
2463
2464 if assigned_cores.is_empty() {
2465 return Err(CommittedCandidateReceiptError::NoAssignment)
2466 }
2467
2468 let descriptor_core_index = CoreIndex(self.descriptor.core_index as u32);
2469
2470 let core_index_selector = if let Some(core_index_selector) = maybe_core_index_selector {
2471 core_index_selector
2473 } else if assigned_cores.len() > 1 {
2474 if !assigned_cores.contains(&descriptor_core_index) {
2476 return Err(CommittedCandidateReceiptError::InvalidCoreIndex)
2478 } else {
2479 return Ok(())
2482 }
2483 } else {
2484 CoreSelector(0)
2486 };
2487
2488 let core_index = assigned_cores
2489 .iter()
2490 .nth(core_index_selector.0 as usize % assigned_cores.len())
2491 .ok_or(CommittedCandidateReceiptError::InvalidSelectedCore)
2492 .copied()?;
2493
2494 if core_index != descriptor_core_index {
2495 return Err(CommittedCandidateReceiptError::CoreIndexMismatch {
2496 descriptor: descriptor_core_index,
2497 commitments: core_index,
2498 })
2499 }
2500
2501 Ok(())
2502 }
2503}
2504
2505#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
2507pub struct BackedCandidate<H = Hash> {
2508 candidate: CommittedCandidateReceiptV2<H>,
2510 validity_votes: Vec<ValidityAttestation>,
2512 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
2516}
2517
2518#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
2520pub struct InherentData<HDR: HeaderT = Header> {
2521 pub bitfields: UncheckedSignedAvailabilityBitfields,
2523 pub backed_candidates: Vec<BackedCandidate<HDR::Hash>>,
2525 pub disputes: MultiDisputeStatementSet,
2527 pub parent_header: HDR,
2529}
2530
2531impl<H> BackedCandidate<H> {
2532 pub fn new(
2534 candidate: CommittedCandidateReceiptV2<H>,
2535 validity_votes: Vec<ValidityAttestation>,
2536 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
2537 core_index: CoreIndex,
2538 ) -> Self {
2539 let mut instance = Self { candidate, validity_votes, validator_indices };
2540 instance.inject_core_index(core_index);
2541 instance
2542 }
2543
2544 pub fn candidate(&self) -> &CommittedCandidateReceiptV2<H> {
2546 &self.candidate
2547 }
2548
2549 #[cfg(feature = "test")]
2552 pub fn candidate_mut(&mut self) -> &mut CommittedCandidateReceiptV2<H> {
2553 &mut self.candidate
2554 }
2555 pub fn descriptor(&self) -> &CandidateDescriptorV2<H> {
2557 &self.candidate.descriptor
2558 }
2559
2560 #[cfg(feature = "test")]
2562 pub fn descriptor_mut(&mut self) -> &mut CandidateDescriptorV2<H> {
2563 &mut self.candidate.descriptor
2564 }
2565
2566 pub fn validity_votes(&self) -> &[ValidityAttestation] {
2568 &self.validity_votes
2569 }
2570
2571 pub fn validity_votes_mut(&mut self) -> &mut Vec<ValidityAttestation> {
2573 &mut self.validity_votes
2574 }
2575
2576 pub fn hash(&self) -> CandidateHash
2578 where
2579 H: Clone + Encode,
2580 {
2581 self.candidate.to_plain().hash()
2582 }
2583
2584 pub fn receipt(&self) -> CandidateReceiptV2<H>
2586 where
2587 H: Clone,
2588 {
2589 self.candidate.to_plain()
2590 }
2591
2592 #[cfg(feature = "test")]
2594 pub fn raw_validator_indices(&self) -> BitVec<u8, bitvec::order::Lsb0> {
2595 self.validator_indices.clone()
2596 }
2597
2598 pub fn validator_indices_and_core_index(
2600 &self,
2601 ) -> (&BitSlice<u8, bitvec::order::Lsb0>, Option<CoreIndex>) {
2602 let core_idx_offset = self.validator_indices.len().saturating_sub(8);
2604 if core_idx_offset > 0 {
2605 let (validator_indices_slice, core_idx_slice) =
2606 self.validator_indices.split_at(core_idx_offset);
2607 return (validator_indices_slice, Some(CoreIndex(core_idx_slice.load::<u8>() as u32)));
2608 }
2609
2610 (&self.validator_indices, None)
2611 }
2612
2613 fn inject_core_index(&mut self, core_index: CoreIndex) {
2615 let core_index_to_inject: BitVec<u8, bitvec::order::Lsb0> =
2616 BitVec::from_vec(vec![core_index.0 as u8]);
2617 self.validator_indices.extend(core_index_to_inject);
2618 }
2619
2620 pub fn set_validator_indices_and_core_index(
2622 &mut self,
2623 new_indices: BitVec<u8, bitvec::order::Lsb0>,
2624 maybe_core_index: Option<CoreIndex>,
2625 ) {
2626 self.validator_indices = new_indices;
2627
2628 if let Some(core_index) = maybe_core_index {
2629 self.inject_core_index(core_index);
2630 }
2631 }
2632}
2633
2634#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
2636#[cfg_attr(feature = "std", derive(PartialEq))]
2637pub struct ScrapedOnChainVotes<H: Encode + Decode = Hash> {
2638 pub session: SessionIndex,
2640 pub backing_validators_per_candidate:
2643 Vec<(CandidateReceiptV2<H>, Vec<(ValidatorIndex, ValidityAttestation)>)>,
2644 pub disputes: MultiDisputeStatementSet,
2648}
2649
2650#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
2652#[cfg_attr(feature = "std", derive(PartialEq))]
2653pub struct OccupiedCore<H = Hash, N = BlockNumber> {
2654 pub next_up_on_available: Option<ScheduledCore>,
2658 pub occupied_since: N,
2660 pub time_out_at: N,
2662 pub next_up_on_time_out: Option<ScheduledCore>,
2666 pub availability: BitVec<u8, bitvec::order::Lsb0>,
2670 pub group_responsible: GroupIndex,
2672 pub candidate_hash: CandidateHash,
2674 pub candidate_descriptor: CandidateDescriptorV2<H>,
2676}
2677
2678impl<H, N> OccupiedCore<H, N> {
2679 pub fn para_id(&self) -> Id {
2681 self.candidate_descriptor.para_id
2682 }
2683}
2684
2685#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
2687#[cfg_attr(feature = "std", derive(PartialEq))]
2688pub enum CoreState<H = Hash, N = BlockNumber> {
2689 #[codec(index = 0)]
2691 Occupied(OccupiedCore<H, N>),
2692 #[codec(index = 1)]
2698 Scheduled(ScheduledCore),
2699 #[codec(index = 2)]
2703 Free,
2704}
2705
2706impl<N> CoreState<N> {
2707 #[deprecated(
2712 note = "`para_id` will be removed. Use `ClaimQueue` to query the scheduled `para_id` instead."
2713 )]
2714 pub fn para_id(&self) -> Option<Id> {
2715 match self {
2716 Self::Occupied(ref core) => core.next_up_on_available.as_ref().map(|n| n.para_id),
2717 Self::Scheduled(core) => Some(core.para_id),
2718 Self::Free => None,
2719 }
2720 }
2721
2722 pub fn is_occupied(&self) -> bool {
2724 matches!(self, Self::Occupied(_))
2725 }
2726}
2727
2728pub type TransposedClaimQueue = BTreeMap<ParaId, BTreeMap<u8, BTreeSet<CoreIndex>>>;
2730
2731pub fn transpose_claim_queue(
2734 claim_queue: BTreeMap<CoreIndex, VecDeque<Id>>,
2735) -> TransposedClaimQueue {
2736 let mut per_para_claim_queue = BTreeMap::new();
2737
2738 for (core, paras) in claim_queue {
2739 for (depth, para) in paras.into_iter().enumerate() {
2741 let depths: &mut BTreeMap<u8, BTreeSet<CoreIndex>> =
2742 per_para_claim_queue.entry(para).or_insert_with(|| Default::default());
2743
2744 depths.entry(depth as u8).or_default().insert(core);
2745 }
2746 }
2747
2748 per_para_claim_queue
2749}
2750
2751#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, DecodeWithMemTracking, TypeInfo, Debug)]
2754pub enum DisputeOffenceKind {
2755 #[codec(index = 0)]
2758 ForInvalidBacked,
2759 #[codec(index = 1)]
2762 AgainstValid,
2763 #[codec(index = 2)]
2766 ForInvalidApproved,
2767}
2768
2769impl From<super::v9::slashing::SlashingOffenceKind> for DisputeOffenceKind {
2773 fn from(value: super::v9::slashing::SlashingOffenceKind) -> Self {
2774 match value {
2775 super::v9::slashing::SlashingOffenceKind::ForInvalid => Self::ForInvalidBacked,
2776 super::v9::slashing::SlashingOffenceKind::AgainstValid => Self::AgainstValid,
2777 }
2778 }
2779}
2780
2781impl TryFrom<DisputeOffenceKind> for super::v9::slashing::SlashingOffenceKind {
2783 type Error = ();
2784
2785 fn try_from(value: DisputeOffenceKind) -> Result<Self, Self::Error> {
2786 match value {
2787 DisputeOffenceKind::ForInvalidBacked => Ok(Self::ForInvalid),
2788 DisputeOffenceKind::AgainstValid => Ok(Self::AgainstValid),
2789 DisputeOffenceKind::ForInvalidApproved => Err(()),
2790 }
2791 }
2792}
2793
2794#[cfg(test)]
2795pub mod tests {
2797 use super::*;
2798
2799 #[test]
2800 fn group_rotation_info_calculations() {
2801 let info =
2802 GroupRotationInfo { session_start_block: 10u32, now: 15, group_rotation_frequency: 5 };
2803
2804 assert_eq!(info.next_rotation_at(), 20);
2805 assert_eq!(info.last_rotation_at(), 15);
2806 }
2807
2808 #[test]
2809 fn group_for_core_is_core_for_group() {
2810 for cores in 1..=256 {
2811 for rotations in 0..(cores * 2) {
2812 let info = GroupRotationInfo {
2813 session_start_block: 0u32,
2814 now: rotations,
2815 group_rotation_frequency: 1,
2816 };
2817
2818 for core in 0..cores {
2819 let group = info.group_for_core(CoreIndex(core), cores as usize);
2820 assert_eq!(info.core_for_group(group, cores as usize).0, core);
2821 }
2822 }
2823 }
2824 }
2825
2826 #[test]
2827 fn test_byzantine_threshold() {
2828 assert_eq!(byzantine_threshold(0), 0);
2829 assert_eq!(byzantine_threshold(1), 0);
2830 assert_eq!(byzantine_threshold(2), 0);
2831 assert_eq!(byzantine_threshold(3), 0);
2832 assert_eq!(byzantine_threshold(4), 1);
2833 assert_eq!(byzantine_threshold(5), 1);
2834 assert_eq!(byzantine_threshold(6), 1);
2835 assert_eq!(byzantine_threshold(7), 2);
2836 }
2837
2838 #[test]
2839 fn test_supermajority_threshold() {
2840 assert_eq!(supermajority_threshold(0), 0);
2841 assert_eq!(supermajority_threshold(1), 1);
2842 assert_eq!(supermajority_threshold(2), 2);
2843 assert_eq!(supermajority_threshold(3), 3);
2844 assert_eq!(supermajority_threshold(4), 3);
2845 assert_eq!(supermajority_threshold(5), 4);
2846 assert_eq!(supermajority_threshold(6), 5);
2847 assert_eq!(supermajority_threshold(7), 5);
2848 }
2849
2850 #[test]
2851 fn balance_bigger_than_usize() {
2852 let zero_b: Balance = 0;
2853 let zero_u: usize = 0;
2854
2855 assert!(zero_b.leading_zeros() >= zero_u.leading_zeros());
2856 }
2857}