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 pezsp_application_crypto::{ByteArray, KeyTypeId};
36use pezsp_arithmetic::{
37 traits::{BaseArithmetic, Saturating},
38 Perbill,
39};
40
41use bounded_collections::BoundedVec;
42use pezsp_core::{ConstU32, RuntimeDebug};
43use pezsp_inherents::InherentIdentifier;
44use serde::{Deserialize, Serialize};
45
46pub use pezsp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
51pub use pezsp_consensus_slots::Slot;
52pub use pezsp_runtime::traits::{AppVerify, BlakeTwo256, Hash as HashT, Header as HeaderT};
53pub use pezsp_staking::SessionIndex;
54
55pub use pezkuwi_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 pezkuwi_teyrchain_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 pezsp_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 TEYRCHAIN_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"para");
108
109mod validator_app {
110 use pezsp_application_crypto::{app_crypto, sr25519};
111 app_crypto!(sr25519, super::TEYRCHAIN_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
185pezsp_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 pezsp_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 TEYRCHAINS_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 pezsp_application_crypto::{app_crypto, sr25519};
488 app_crypto!(sr25519, super::ASSIGNMENT_KEY_TYPE_ID);
489}
490
491pub type AssignmentId = assignment_app::Public;
494
495pezsp_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 PEZKUWI_ENGINE_ID: pezsp_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: &pezsp_runtime::DigestItem,
1068 ) -> Result<Option<Self>, codec::Error> {
1069 match digest_item {
1070 pezsp_runtime::DigestItem::Consensus(id, encoded) if id == &PEZKUWI_ENGINE_ID => {
1071 Ok(Some(Self::decode(&mut &encoded[..])?))
1072 },
1073 _ => Ok(None),
1074 }
1075 }
1076}
1077
1078impl From<ConsensusLog> for pezsp_runtime::DigestItem {
1079 fn from(c: ConsensusLog) -> pezsp_runtime::DigestItem {
1080 Self::Consensus(PEZKUWI_ENGINE_ID, c.encode())
1081 }
1082}
1083
1084#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1088pub enum DisputeStatement {
1089 #[codec(index = 0)]
1091 Valid(ValidDisputeStatementKind),
1092 #[codec(index = 1)]
1094 Invalid(InvalidDisputeStatementKind),
1095}
1096
1097impl DisputeStatement {
1098 pub fn payload_data(
1103 &self,
1104 candidate_hash: CandidateHash,
1105 session: SessionIndex,
1106 ) -> Result<Vec<u8>, ()> {
1107 match self {
1108 DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) => {
1109 Ok(ExplicitDisputeStatement { valid: true, candidate_hash, session }
1110 .signing_payload())
1111 },
1112 DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded(
1113 inclusion_parent,
1114 )) => Ok(CompactStatement::Seconded(candidate_hash).signing_payload(&SigningContext {
1115 session_index: session,
1116 parent_hash: *inclusion_parent,
1117 })),
1118 DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent)) => {
1119 Ok(CompactStatement::Valid(candidate_hash).signing_payload(&SigningContext {
1120 session_index: session,
1121 parent_hash: *inclusion_parent,
1122 }))
1123 },
1124 DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) => {
1125 Ok(ApprovalVote(candidate_hash).signing_payload(session))
1126 },
1127 DisputeStatement::Valid(
1128 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes),
1129 ) => {
1130 if candidate_hashes.contains(&candidate_hash) {
1131 Ok(ApprovalVoteMultipleCandidates(candidate_hashes).signing_payload(session))
1132 } else {
1133 Err(())
1134 }
1135 },
1136 DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit) => {
1137 Ok(ExplicitDisputeStatement { valid: false, candidate_hash, session }
1138 .signing_payload())
1139 },
1140 }
1141 }
1142
1143 pub fn check_signature(
1145 &self,
1146 validator_public: &ValidatorId,
1147 candidate_hash: CandidateHash,
1148 session: SessionIndex,
1149 validator_signature: &ValidatorSignature,
1150 ) -> Result<(), ()> {
1151 let payload = self.payload_data(candidate_hash, session)?;
1152
1153 if validator_signature.verify(&payload[..], &validator_public) {
1154 Ok(())
1155 } else {
1156 Err(())
1157 }
1158 }
1159
1160 pub fn indicates_validity(&self) -> bool {
1162 match *self {
1163 DisputeStatement::Valid(_) => true,
1164 DisputeStatement::Invalid(_) => false,
1165 }
1166 }
1167
1168 pub fn indicates_invalidity(&self) -> bool {
1170 match *self {
1171 DisputeStatement::Valid(_) => false,
1172 DisputeStatement::Invalid(_) => true,
1173 }
1174 }
1175
1176 pub fn is_backing(&self) -> bool {
1178 match self {
1179 Self::Valid(s) => s.is_backing(),
1180 Self::Invalid(_) => false,
1181 }
1182 }
1183}
1184
1185#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1187pub enum ValidDisputeStatementKind {
1188 #[codec(index = 0)]
1190 Explicit,
1191 #[codec(index = 1)]
1193 BackingSeconded(Hash),
1194 #[codec(index = 2)]
1196 BackingValid(Hash),
1197 #[codec(index = 3)]
1199 ApprovalChecking,
1200 #[codec(index = 4)]
1205 ApprovalCheckingMultipleCandidates(Vec<CandidateHash>),
1206}
1207
1208impl ValidDisputeStatementKind {
1209 pub fn is_backing(&self) -> bool {
1211 match self {
1212 ValidDisputeStatementKind::BackingSeconded(_)
1213 | ValidDisputeStatementKind::BackingValid(_) => true,
1214 ValidDisputeStatementKind::Explicit
1215 | ValidDisputeStatementKind::ApprovalChecking
1216 | ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(_) => false,
1217 }
1218 }
1219}
1220
1221#[derive(Encode, Decode, DecodeWithMemTracking, Copy, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1223pub enum InvalidDisputeStatementKind {
1224 #[codec(index = 0)]
1226 Explicit,
1227}
1228
1229#[derive(Clone, PartialEq, RuntimeDebug)]
1231pub struct ExplicitDisputeStatement {
1232 pub valid: bool,
1234 pub candidate_hash: CandidateHash,
1236 pub session: SessionIndex,
1238}
1239
1240impl ExplicitDisputeStatement {
1241 pub fn signing_payload(&self) -> Vec<u8> {
1243 const MAGIC: [u8; 4] = *b"DISP";
1244
1245 (MAGIC, self.valid, self.candidate_hash, self.session).encode()
1246 }
1247}
1248
1249#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1251pub struct DisputeStatementSet {
1252 pub candidate_hash: CandidateHash,
1254 pub session: SessionIndex,
1256 pub statements: Vec<(DisputeStatement, ValidatorIndex, ValidatorSignature)>,
1258}
1259
1260impl From<CheckedDisputeStatementSet> for DisputeStatementSet {
1261 fn from(other: CheckedDisputeStatementSet) -> Self {
1262 other.0
1263 }
1264}
1265
1266impl AsRef<DisputeStatementSet> for DisputeStatementSet {
1267 fn as_ref(&self) -> &DisputeStatementSet {
1268 &self
1269 }
1270}
1271
1272pub type MultiDisputeStatementSet = Vec<DisputeStatementSet>;
1274
1275#[derive(Clone, PartialEq, RuntimeDebug, Encode)]
1277pub struct CheckedDisputeStatementSet(DisputeStatementSet);
1278
1279impl AsRef<DisputeStatementSet> for CheckedDisputeStatementSet {
1280 fn as_ref(&self) -> &DisputeStatementSet {
1281 &self.0
1282 }
1283}
1284
1285impl core::cmp::PartialEq<DisputeStatementSet> for CheckedDisputeStatementSet {
1286 fn eq(&self, other: &DisputeStatementSet) -> bool {
1287 self.0.eq(other)
1288 }
1289}
1290
1291impl CheckedDisputeStatementSet {
1292 pub fn unchecked_from_unchecked(unchecked: DisputeStatementSet) -> Self {
1295 Self(unchecked)
1296 }
1297}
1298
1299pub type CheckedMultiDisputeStatementSet = Vec<CheckedDisputeStatementSet>;
1301
1302#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, TypeInfo)]
1304pub struct DisputeState<N = BlockNumber> {
1305 pub validators_for: BitVec<u8, bitvec::order::Lsb0>, pub validators_against: BitVec<u8, bitvec::order::Lsb0>, pub start: N,
1311 pub concluded_at: Option<N>,
1313}
1314
1315#[derive(Clone, Eq, PartialEq, Decode, DecodeWithMemTracking, Encode, RuntimeDebug, TypeInfo)]
1318pub enum ValidityAttestation {
1319 #[codec(index = 1)]
1322 Implicit(ValidatorSignature),
1323 #[codec(index = 2)]
1326 Explicit(ValidatorSignature),
1327}
1328
1329impl ValidityAttestation {
1330 pub fn to_compact_statement(&self, candidate_hash: CandidateHash) -> CompactStatement {
1333 match *self {
1337 ValidityAttestation::Implicit(_) => CompactStatement::Seconded(candidate_hash),
1338 ValidityAttestation::Explicit(_) => CompactStatement::Valid(candidate_hash),
1339 }
1340 }
1341
1342 pub fn signature(&self) -> &ValidatorSignature {
1344 match *self {
1345 ValidityAttestation::Implicit(ref sig) => sig,
1346 ValidityAttestation::Explicit(ref sig) => sig,
1347 }
1348 }
1349
1350 pub fn signed_payload<H: Encode>(
1353 &self,
1354 candidate_hash: CandidateHash,
1355 signing_context: &SigningContext<H>,
1356 ) -> Vec<u8> {
1357 match *self {
1358 ValidityAttestation::Implicit(_) => {
1359 (CompactStatement::Seconded(candidate_hash), signing_context).encode()
1360 },
1361 ValidityAttestation::Explicit(_) => {
1362 (CompactStatement::Valid(candidate_hash), signing_context).encode()
1363 },
1364 }
1365 }
1366}
1367
1368#[derive(Clone, Eq, PartialEq, Default, Decode, Encode, RuntimeDebug)]
1370pub struct SigningContext<H = Hash> {
1371 pub session_index: pezsp_staking::SessionIndex,
1373 pub parent_hash: H,
1375}
1376
1377const BACKING_STATEMENT_MAGIC: [u8; 4] = *b"BKNG";
1378
1379#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
1382#[cfg_attr(feature = "std", derive(Hash))]
1383pub enum CompactStatement {
1384 Seconded(CandidateHash),
1386 Valid(CandidateHash),
1388}
1389
1390impl CompactStatement {
1391 pub fn signing_payload(&self, context: &SigningContext) -> Vec<u8> {
1394 (self, context).encode()
1395 }
1396
1397 pub fn candidate_hash(&self) -> &CandidateHash {
1399 match *self {
1400 CompactStatement::Seconded(ref h) | CompactStatement::Valid(ref h) => h,
1401 }
1402 }
1403}
1404
1405#[derive(Encode, Decode, TypeInfo)]
1407enum CompactStatementInner {
1408 #[codec(index = 1)]
1409 Seconded(CandidateHash),
1410 #[codec(index = 2)]
1411 Valid(CandidateHash),
1412}
1413
1414impl From<CompactStatement> for CompactStatementInner {
1415 fn from(s: CompactStatement) -> Self {
1416 match s {
1417 CompactStatement::Seconded(h) => CompactStatementInner::Seconded(h),
1418 CompactStatement::Valid(h) => CompactStatementInner::Valid(h),
1419 }
1420 }
1421}
1422
1423impl codec::Encode for CompactStatement {
1424 fn size_hint(&self) -> usize {
1425 4 + 1 + 32
1427 }
1428
1429 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
1430 dest.write(&BACKING_STATEMENT_MAGIC);
1431 CompactStatementInner::from(self.clone()).encode_to(dest)
1432 }
1433}
1434
1435impl codec::Decode for CompactStatement {
1436 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
1437 let maybe_magic = <[u8; 4]>::decode(input)?;
1438 if maybe_magic != BACKING_STATEMENT_MAGIC {
1439 return Err(codec::Error::from("invalid magic string"));
1440 }
1441
1442 Ok(match CompactStatementInner::decode(input)? {
1443 CompactStatementInner::Seconded(h) => CompactStatement::Seconded(h),
1444 CompactStatementInner::Valid(h) => CompactStatement::Valid(h),
1445 })
1446 }
1447}
1448
1449#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1451#[cfg_attr(feature = "std", derive(PartialEq))]
1452pub struct IndexedVec<K, V>(Vec<V>, PhantomData<fn(K) -> K>);
1453
1454impl<K, V> Default for IndexedVec<K, V> {
1455 fn default() -> Self {
1456 Self(vec![], PhantomData)
1457 }
1458}
1459
1460impl<K, V> From<Vec<V>> for IndexedVec<K, V> {
1461 fn from(validators: Vec<V>) -> Self {
1462 Self(validators, PhantomData)
1463 }
1464}
1465
1466impl<K, V> FromIterator<V> for IndexedVec<K, V> {
1467 fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
1468 Self(Vec::from_iter(iter), PhantomData)
1469 }
1470}
1471
1472impl<K, V> IndexedVec<K, V>
1473where
1474 V: Clone,
1475{
1476 pub fn get(&self, index: K) -> Option<&V>
1478 where
1479 K: TypeIndex,
1480 {
1481 self.0.get(index.type_index())
1482 }
1483
1484 pub fn get_mut(&mut self, index: K) -> Option<&mut V>
1486 where
1487 K: TypeIndex,
1488 {
1489 self.0.get_mut(index.type_index())
1490 }
1491
1492 pub fn len(&self) -> usize {
1494 self.0.len()
1495 }
1496
1497 pub fn to_vec(&self) -> Vec<V> {
1499 self.0.clone()
1500 }
1501
1502 pub fn iter(&self) -> Iter<'_, V> {
1504 self.0.iter()
1505 }
1506
1507 pub fn iter_mut(&mut self) -> IterMut<'_, V> {
1509 self.0.iter_mut()
1510 }
1511
1512 pub fn into_iter(self) -> IntoIter<V> {
1514 self.0.into_iter()
1515 }
1516
1517 pub fn is_empty(&self) -> bool {
1519 self.0.is_empty()
1520 }
1521}
1522
1523pub const fn byzantine_threshold(n: usize) -> usize {
1527 n.saturating_sub(1) / 3
1528}
1529
1530pub const fn supermajority_threshold(n: usize) -> usize {
1533 n - byzantine_threshold(n)
1534}
1535
1536pub fn effective_minimum_backing_votes(
1538 group_len: usize,
1539 configured_minimum_backing_votes: u32,
1540) -> usize {
1541 core::cmp::min(group_len, configured_minimum_backing_votes as usize)
1542}
1543
1544#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
1549#[cfg_attr(feature = "std", derive(PartialEq))]
1550pub struct SessionInfo {
1551 pub active_validator_indices: Vec<ValidatorIndex>,
1555 pub random_seed: [u8; 32],
1557 pub dispute_period: SessionIndex,
1559
1560 pub validators: IndexedVec<ValidatorIndex, ValidatorId>,
1568 pub discovery_keys: Vec<AuthorityDiscoveryId>,
1574 pub assignment_keys: Vec<AssignmentId>,
1584 pub validator_groups: IndexedVec<GroupIndex, Vec<ValidatorIndex>>,
1588 pub n_cores: u32,
1590 pub zeroth_delay_tranche_width: u32,
1592 pub relay_vrf_modulo_samples: u32,
1594 pub n_delay_tranches: u32,
1596 pub no_show_slots: u32,
1599 pub needed_approvals: u32,
1601}
1602
1603#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
1606pub struct PvfCheckStatement {
1607 pub accept: bool,
1609 pub subject: ValidationCodeHash,
1611 pub session_index: SessionIndex,
1613 pub validator_index: ValidatorIndex,
1615}
1616
1617impl PvfCheckStatement {
1618 pub fn signing_payload(&self) -> Vec<u8> {
1623 const MAGIC: [u8; 4] = *b"VCPC"; (MAGIC, self.accept, self.subject, self.session_index, self.validator_index).encode()
1625 }
1626}
1627
1628pub struct WellKnownKey<T> {
1632 pub key: Vec<u8>,
1634 _p: core::marker::PhantomData<T>,
1635}
1636
1637impl<T> From<Vec<u8>> for WellKnownKey<T> {
1638 fn from(key: Vec<u8>) -> Self {
1639 Self { key, _p: Default::default() }
1640 }
1641}
1642
1643impl<T> AsRef<[u8]> for WellKnownKey<T> {
1644 fn as_ref(&self) -> &[u8] {
1645 self.key.as_ref()
1646 }
1647}
1648
1649impl<T: Decode> WellKnownKey<T> {
1650 pub fn get(&self) -> Option<T> {
1652 pezsp_io::storage::get(&self.key)
1653 .and_then(|raw| codec::DecodeAll::decode_all(&mut raw.as_ref()).ok())
1654 }
1655}
1656
1657impl<T: Encode> WellKnownKey<T> {
1658 pub fn set(&self, value: T) {
1660 pezsp_io::storage::set(&self.key, &value.encode());
1661 }
1662}
1663
1664#[derive(
1666 Encode,
1667 Decode,
1668 DecodeWithMemTracking,
1669 TypeInfo,
1670 Clone,
1671 Copy,
1672 Debug,
1673 PartialEq,
1674 Eq,
1675 Serialize,
1676 Deserialize,
1677)]
1678pub enum PvfPrepKind {
1679 Precheck,
1681
1682 Prepare,
1684}
1685
1686#[derive(
1688 Encode,
1689 Decode,
1690 DecodeWithMemTracking,
1691 TypeInfo,
1692 Clone,
1693 Copy,
1694 Debug,
1695 PartialEq,
1696 Eq,
1697 Serialize,
1698 Deserialize,
1699)]
1700pub enum PvfExecKind {
1701 Backing,
1703 Approval,
1705}
1706
1707pub type NodeFeatures = BitVec<u8, bitvec::order::Lsb0>;
1709
1710pub mod node_features {
1712 #[repr(u8)]
1715 #[derive(Clone, Copy)]
1716 pub enum FeatureIndex {
1717 EnableAssignmentsV2 = 0,
1720 ElasticScalingMVP = 1,
1724 AvailabilityChunkMapping = 2,
1730 CandidateReceiptV2 = 3,
1734 FirstUnassigned = 4,
1738 }
1739}
1740
1741#[derive(
1743 RuntimeDebug,
1744 Copy,
1745 Clone,
1746 PartialEq,
1747 Encode,
1748 Decode,
1749 DecodeWithMemTracking,
1750 TypeInfo,
1751 serde::Serialize,
1752 serde::Deserialize,
1753)]
1754pub struct SchedulerParams<BlockNumber> {
1755 pub group_rotation_frequency: BlockNumber,
1759 pub paras_availability_period: BlockNumber,
1774 pub max_validators_per_core: Option<u32>,
1778 pub lookahead: u32,
1780 pub num_cores: u32,
1782 #[deprecated]
1785 pub max_availability_timeouts: u32,
1786 pub on_demand_queue_max_size: u32,
1788 pub on_demand_target_queue_utilization: Perbill,
1790 pub on_demand_fee_variability: Perbill,
1793 pub on_demand_base_fee: Balance,
1795 #[deprecated]
1798 pub ttl: BlockNumber,
1799}
1800
1801impl<BlockNumber: Default + From<u32>> Default for SchedulerParams<BlockNumber> {
1802 #[allow(deprecated)]
1803 fn default() -> Self {
1804 Self {
1805 group_rotation_frequency: 1u32.into(),
1806 paras_availability_period: 1u32.into(),
1807 max_validators_per_core: Default::default(),
1808 lookahead: 1,
1809 num_cores: Default::default(),
1810 max_availability_timeouts: Default::default(),
1811 on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE,
1812 on_demand_target_queue_utilization: Perbill::from_percent(25),
1813 on_demand_fee_variability: Perbill::from_percent(3),
1814 on_demand_base_fee: 10_000_000u128,
1815 ttl: 5u32.into(),
1816 }
1817 }
1818}
1819
1820#[derive(
1822 PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, Clone, TypeInfo, RuntimeDebug, Copy,
1823)]
1824pub struct InternalVersion(pub u8);
1825
1826#[derive(PartialEq, Eq, Clone, TypeInfo, RuntimeDebug)]
1828pub enum CandidateDescriptorVersion {
1829 V1,
1831 V2,
1833 Unknown,
1835}
1836
1837#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
1839pub struct CandidateDescriptorV2<H = Hash> {
1840 pub(super) para_id: ParaId,
1842 relay_parent: H,
1844 pub(super) version: InternalVersion,
1849 pub(super) core_index: u16,
1851 session_index: SessionIndex,
1853 reserved1: [u8; 25],
1855 persisted_validation_data_hash: Hash,
1859 pov_hash: Hash,
1861 erasure_root: Hash,
1863 reserved2: [u8; 64],
1865 para_head: Hash,
1867 validation_code_hash: ValidationCodeHash,
1869}
1870
1871impl<H> CandidateDescriptorV2<H> {
1872 pub fn version(&self) -> CandidateDescriptorVersion {
1877 if self.reserved2 != [0u8; 64] || self.reserved1 != [0u8; 25] {
1878 return CandidateDescriptorVersion::V1;
1879 }
1880
1881 match self.version.0 {
1882 0 => CandidateDescriptorVersion::V2,
1883 _ => CandidateDescriptorVersion::Unknown,
1884 }
1885 }
1886}
1887
1888macro_rules! impl_getter {
1889 ($field:ident, $type:ident) => {
1890 pub fn $field(&self) -> $type {
1892 self.$field
1893 }
1894 };
1895}
1896
1897impl<H: Copy> CandidateDescriptorV2<H> {
1898 impl_getter!(erasure_root, Hash);
1899 impl_getter!(para_head, Hash);
1900 impl_getter!(relay_parent, H);
1901 impl_getter!(para_id, ParaId);
1902 impl_getter!(persisted_validation_data_hash, Hash);
1903 impl_getter!(pov_hash, Hash);
1904 impl_getter!(validation_code_hash, ValidationCodeHash);
1905
1906 fn rebuild_collator_field(&self) -> CollatorId {
1907 let mut collator_id = Vec::with_capacity(32);
1908 let core_index: [u8; 2] = self.core_index.to_ne_bytes();
1909 let session_index: [u8; 4] = self.session_index.to_ne_bytes();
1910
1911 collator_id.push(self.version.0);
1912 collator_id.extend_from_slice(core_index.as_slice());
1913 collator_id.extend_from_slice(session_index.as_slice());
1914 collator_id.extend_from_slice(self.reserved1.as_slice());
1915
1916 CollatorId::from_slice(&collator_id.as_slice())
1917 .expect("Slice size is exactly 32 bytes; qed")
1918 }
1919
1920 #[cfg(feature = "test")]
1921 #[doc(hidden)]
1922 pub fn rebuild_collator_field_for_tests(&self) -> CollatorId {
1923 self.rebuild_collator_field()
1924 }
1925
1926 pub fn collator(&self) -> Option<CollatorId> {
1928 if self.version() == CandidateDescriptorVersion::V1 {
1929 Some(self.rebuild_collator_field())
1930 } else {
1931 None
1932 }
1933 }
1934
1935 fn rebuild_signature_field(&self) -> CollatorSignature {
1936 CollatorSignature::from_slice(self.reserved2.as_slice())
1937 .expect("Slice size is exactly 64 bytes; qed")
1938 }
1939
1940 #[cfg(feature = "test")]
1941 #[doc(hidden)]
1942 pub fn rebuild_signature_field_for_tests(&self) -> CollatorSignature {
1943 self.rebuild_signature_field()
1944 }
1945
1946 pub fn signature(&self) -> Option<CollatorSignature> {
1948 if self.version() == CandidateDescriptorVersion::V1 {
1949 return Some(self.rebuild_signature_field());
1950 }
1951
1952 None
1953 }
1954
1955 pub fn core_index(&self) -> Option<CoreIndex> {
1957 if self.version() == CandidateDescriptorVersion::V1 {
1958 return None;
1959 }
1960
1961 Some(CoreIndex(self.core_index as u32))
1962 }
1963
1964 pub fn session_index(&self) -> Option<SessionIndex> {
1966 if self.version() == CandidateDescriptorVersion::V1 {
1967 return None;
1968 }
1969
1970 Some(self.session_index)
1971 }
1972}
1973
1974impl<H> core::fmt::Debug for CandidateDescriptorV2<H>
1975where
1976 H: core::fmt::Debug,
1977{
1978 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1979 match self.version() {
1980 CandidateDescriptorVersion::V1 => f
1981 .debug_struct("CandidateDescriptorV1")
1982 .field("para_id", &self.para_id)
1983 .field("relay_parent", &self.relay_parent)
1984 .field("persisted_validation_hash", &self.persisted_validation_data_hash)
1985 .field("pov_hash", &self.pov_hash)
1986 .field("erasure_root", &self.erasure_root)
1987 .field("para_head", &self.para_head)
1988 .field("validation_code_hash", &self.validation_code_hash)
1989 .finish(),
1990 CandidateDescriptorVersion::V2 => f
1991 .debug_struct("CandidateDescriptorV2")
1992 .field("para_id", &self.para_id)
1993 .field("relay_parent", &self.relay_parent)
1994 .field("core_index", &self.core_index)
1995 .field("session_index", &self.session_index)
1996 .field("persisted_validation_data_hash", &self.persisted_validation_data_hash)
1997 .field("pov_hash", &self.pov_hash)
1998 .field("erasure_root", &self.pov_hash)
1999 .field("para_head", &self.para_head)
2000 .field("validation_code_hash", &self.validation_code_hash)
2001 .finish(),
2002 CandidateDescriptorVersion::Unknown => {
2003 write!(f, "Invalid CandidateDescriptorVersion")
2004 },
2005 }
2006 }
2007}
2008
2009impl<H: Copy + AsRef<[u8]>> CandidateDescriptorV2<H> {
2010 pub fn new(
2012 para_id: Id,
2013 relay_parent: H,
2014 core_index: CoreIndex,
2015 session_index: SessionIndex,
2016 persisted_validation_data_hash: Hash,
2017 pov_hash: Hash,
2018 erasure_root: Hash,
2019 para_head: Hash,
2020 validation_code_hash: ValidationCodeHash,
2021 ) -> Self {
2022 Self {
2023 para_id,
2024 relay_parent,
2025 version: InternalVersion(0),
2026 core_index: core_index.0 as u16,
2027 session_index,
2028 reserved1: [0; 25],
2029 persisted_validation_data_hash,
2030 pov_hash,
2031 erasure_root,
2032 reserved2: [0; 64],
2033 para_head,
2034 validation_code_hash,
2035 }
2036 }
2037
2038 #[cfg(feature = "test")]
2039 #[doc(hidden)]
2040 pub fn new_from_raw(
2041 para_id: Id,
2042 relay_parent: H,
2043 version: InternalVersion,
2044 core_index: u16,
2045 session_index: SessionIndex,
2046 reserved1: [u8; 25],
2047 persisted_validation_data_hash: Hash,
2048 pov_hash: Hash,
2049 erasure_root: Hash,
2050 reserved2: [u8; 64],
2051 para_head: Hash,
2052 validation_code_hash: ValidationCodeHash,
2053 ) -> Self {
2054 Self {
2055 para_id,
2056 relay_parent,
2057 version,
2058 core_index,
2059 session_index,
2060 reserved1,
2061 persisted_validation_data_hash,
2062 pov_hash,
2063 erasure_root,
2064 reserved2,
2065 para_head,
2066 validation_code_hash,
2067 }
2068 }
2069}
2070
2071#[cfg(feature = "test")]
2073pub trait MutateDescriptorV2<H> {
2074 fn set_relay_parent(&mut self, relay_parent: H);
2076 fn set_para_id(&mut self, para_id: Id);
2078 fn set_pov_hash(&mut self, pov_hash: Hash);
2080 fn set_version(&mut self, version: InternalVersion);
2082 fn set_persisted_validation_data_hash(&mut self, persisted_validation_data_hash: Hash);
2084 fn set_validation_code_hash(&mut self, validation_code_hash: ValidationCodeHash);
2086 fn set_erasure_root(&mut self, erasure_root: Hash);
2088 fn set_para_head(&mut self, para_head: Hash);
2090 fn set_core_index(&mut self, core_index: CoreIndex);
2092 fn set_session_index(&mut self, session_index: SessionIndex);
2094 fn set_reserved2(&mut self, reserved2: [u8; 64]);
2096}
2097
2098#[cfg(feature = "test")]
2099impl<H> MutateDescriptorV2<H> for CandidateDescriptorV2<H> {
2100 fn set_para_id(&mut self, para_id: Id) {
2101 self.para_id = para_id;
2102 }
2103
2104 fn set_relay_parent(&mut self, relay_parent: H) {
2105 self.relay_parent = relay_parent;
2106 }
2107
2108 fn set_pov_hash(&mut self, pov_hash: Hash) {
2109 self.pov_hash = pov_hash;
2110 }
2111
2112 fn set_version(&mut self, version: InternalVersion) {
2113 self.version = version;
2114 }
2115
2116 fn set_core_index(&mut self, core_index: CoreIndex) {
2117 self.core_index = core_index.0 as u16;
2118 }
2119
2120 fn set_session_index(&mut self, session_index: SessionIndex) {
2121 self.session_index = session_index;
2122 }
2123
2124 fn set_persisted_validation_data_hash(&mut self, persisted_validation_data_hash: Hash) {
2125 self.persisted_validation_data_hash = persisted_validation_data_hash;
2126 }
2127
2128 fn set_validation_code_hash(&mut self, validation_code_hash: ValidationCodeHash) {
2129 self.validation_code_hash = validation_code_hash;
2130 }
2131
2132 fn set_erasure_root(&mut self, erasure_root: Hash) {
2133 self.erasure_root = erasure_root;
2134 }
2135
2136 fn set_para_head(&mut self, para_head: Hash) {
2137 self.para_head = para_head;
2138 }
2139
2140 fn set_reserved2(&mut self, reserved2: [u8; 64]) {
2141 self.reserved2 = reserved2;
2142 }
2143}
2144
2145#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
2147pub struct CandidateReceiptV2<H = Hash> {
2148 pub descriptor: CandidateDescriptorV2<H>,
2150 pub commitments_hash: Hash,
2152}
2153
2154#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
2156pub struct CommittedCandidateReceiptV2<H = Hash> {
2157 pub descriptor: CandidateDescriptorV2<H>,
2159 pub commitments: CandidateCommitments,
2161}
2162
2163#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
2165#[cfg_attr(feature = "std", derive(PartialEq))]
2166pub enum CandidateEvent<H = Hash> {
2167 #[codec(index = 0)]
2170 CandidateBacked(CandidateReceiptV2<H>, HeadData, CoreIndex, GroupIndex),
2171 #[codec(index = 1)]
2175 CandidateIncluded(CandidateReceiptV2<H>, HeadData, CoreIndex, GroupIndex),
2176 #[codec(index = 2)]
2179 CandidateTimedOut(CandidateReceiptV2<H>, HeadData, CoreIndex),
2180}
2181
2182impl<H> CandidateReceiptV2<H> {
2183 pub fn descriptor(&self) -> &CandidateDescriptorV2<H> {
2185 &self.descriptor
2186 }
2187
2188 pub fn hash(&self) -> CandidateHash
2190 where
2191 H: Encode,
2192 {
2193 CandidateHash(BlakeTwo256::hash_of(self))
2194 }
2195}
2196
2197impl<H: Clone> CommittedCandidateReceiptV2<H> {
2198 pub fn to_plain(&self) -> CandidateReceiptV2<H> {
2200 CandidateReceiptV2 {
2201 descriptor: self.descriptor.clone(),
2202 commitments_hash: self.commitments.hash(),
2203 }
2204 }
2205
2206 pub fn hash(&self) -> CandidateHash
2211 where
2212 H: Encode,
2213 {
2214 self.to_plain().hash()
2215 }
2216
2217 pub fn corresponds_to(&self, receipt: &CandidateReceiptV2<H>) -> bool
2219 where
2220 H: PartialEq,
2221 {
2222 receipt.descriptor == self.descriptor && receipt.commitments_hash == self.commitments.hash()
2223 }
2224}
2225
2226impl PartialOrd for CommittedCandidateReceiptV2 {
2227 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
2228 Some(self.cmp(other))
2229 }
2230}
2231
2232impl Ord for CommittedCandidateReceiptV2 {
2233 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
2234 self.descriptor
2235 .para_id
2236 .cmp(&other.descriptor.para_id)
2237 .then_with(|| self.commitments.head_data.cmp(&other.commitments.head_data))
2238 }
2239}
2240
2241#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Debug, Copy)]
2244pub struct CoreSelector(pub u8);
2245
2246#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Debug, Copy)]
2248pub struct ClaimQueueOffset(pub u8);
2249
2250#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Debug)]
2252pub enum UMPSignal {
2253 SelectCore(CoreSelector, ClaimQueueOffset),
2257 ApprovedPeer(ApprovedPeerId),
2259}
2260
2261pub const DEFAULT_CLAIM_QUEUE_OFFSET: u8 = 0;
2264
2265pub type ApprovedPeerId = BoundedVec<u8, ConstU32<64>>;
2269
2270#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug, Default)]
2271pub struct CandidateUMPSignals {
2273 pub(super) select_core: Option<(CoreSelector, ClaimQueueOffset)>,
2274 pub(super) approved_peer: Option<ApprovedPeerId>,
2275}
2276
2277impl CandidateUMPSignals {
2278 pub fn core_selector(&self) -> Option<(CoreSelector, ClaimQueueOffset)> {
2280 self.select_core
2281 }
2282
2283 pub fn approved_peer(&self) -> Option<&ApprovedPeerId> {
2285 self.approved_peer.as_ref()
2286 }
2287
2288 pub fn is_empty(&self) -> bool {
2290 self.select_core.is_none() && self.approved_peer.is_none()
2291 }
2292
2293 fn try_decode_signal(
2294 &mut self,
2295 buffer: &mut impl codec::Input,
2296 ) -> Result<(), CommittedCandidateReceiptError> {
2297 match UMPSignal::decode(buffer)
2298 .map_err(|_| CommittedCandidateReceiptError::UmpSignalDecode)?
2299 {
2300 UMPSignal::ApprovedPeer(approved_peer_id) if self.approved_peer.is_none() => {
2301 self.approved_peer = Some(approved_peer_id);
2302 },
2303 UMPSignal::SelectCore(core_selector, cq_offset) if self.select_core.is_none() => {
2304 self.select_core = Some((core_selector, cq_offset));
2305 },
2306 _ => {
2307 return Err(CommittedCandidateReceiptError::DuplicateUMPSignal);
2309 },
2310 };
2311
2312 Ok(())
2313 }
2314
2315 #[cfg(feature = "test")]
2316 #[doc(hidden)]
2317 pub fn dummy(
2318 select_core: Option<(CoreSelector, ClaimQueueOffset)>,
2319 approved_peer: Option<ApprovedPeerId>,
2320 ) -> Self {
2321 Self { select_core, approved_peer }
2322 }
2323}
2324
2325pub const UMP_SEPARATOR: Vec<u8> = vec![];
2327
2328pub fn skip_ump_signals<'a>(
2330 upward_messages: impl Iterator<Item = &'a Vec<u8>>,
2331) -> impl Iterator<Item = &'a Vec<u8>> {
2332 upward_messages.take_while(|message| *message != &UMP_SEPARATOR)
2333}
2334
2335impl CandidateCommitments {
2336 pub fn ump_signals(&self) -> Result<CandidateUMPSignals, CommittedCandidateReceiptError> {
2339 let mut res = CandidateUMPSignals::default();
2340
2341 let mut signals_iter =
2342 self.upward_messages.iter().skip_while(|message| *message != &UMP_SEPARATOR);
2343
2344 if signals_iter.next().is_none() {
2345 return Ok(res);
2347 }
2348
2349 let Some(first_signal) = signals_iter.next() else { return Ok(res) };
2351 res.try_decode_signal(&mut first_signal.as_slice())?;
2352
2353 let Some(second_signal) = signals_iter.next() else { return Ok(res) };
2355 res.try_decode_signal(&mut second_signal.as_slice())?;
2356
2357 if signals_iter.next().is_some() {
2359 return Err(CommittedCandidateReceiptError::TooManyUMPSignals);
2360 }
2361
2362 Ok(res)
2363 }
2364}
2365
2366#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
2368#[cfg_attr(feature = "std", derive(thiserror::Error))]
2369pub enum CommittedCandidateReceiptError {
2370 #[cfg_attr(feature = "std", error("The specified core index is invalid"))]
2372 InvalidCoreIndex,
2373 #[cfg_attr(
2375 feature = "std",
2376 error("The core index in commitments ({commitments:?}) doesn't match the one in descriptor ({descriptor:?})")
2377 )]
2378 CoreIndexMismatch {
2379 descriptor: CoreIndex,
2381 commitments: CoreIndex,
2383 },
2384 #[cfg_attr(feature = "std", error("The core selector or claim queue offset is invalid"))]
2386 InvalidSelectedCore,
2387 #[cfg_attr(feature = "std", error("Could not decode UMP signal"))]
2388 UmpSignalDecode,
2390 #[cfg_attr(
2392 feature = "std",
2393 error("The teyrchain is not assigned to any core at specified claim queue offset")
2394 )]
2395 NoAssignment,
2396 #[cfg_attr(feature = "std", error("Unknown internal version"))]
2398 UnknownVersion(InternalVersion),
2399 #[cfg_attr(feature = "std", error("Too many UMP signals"))]
2401 TooManyUMPSignals,
2402 #[cfg_attr(feature = "std", error("Duplicate UMP signal"))]
2404 DuplicateUMPSignal,
2405 #[cfg_attr(feature = "std", error("Version 1 receipt does not support ump signals"))]
2408 UMPSignalWithV1Decriptor,
2409}
2410
2411impl<H: Copy> CommittedCandidateReceiptV2<H> {
2412 pub fn parse_ump_signals(
2420 &self,
2421 cores_per_para: &TransposedClaimQueue,
2422 ) -> Result<CandidateUMPSignals, CommittedCandidateReceiptError> {
2423 let signals = self.commitments.ump_signals()?;
2424
2425 match self.descriptor.version() {
2426 CandidateDescriptorVersion::V1 => {
2427 if !signals.is_empty() {
2430 return Err(CommittedCandidateReceiptError::UMPSignalWithV1Decriptor);
2431 } else {
2432 return Ok(CandidateUMPSignals::default());
2434 }
2435 },
2436 CandidateDescriptorVersion::V2 => {},
2437 CandidateDescriptorVersion::Unknown => {
2438 return Err(CommittedCandidateReceiptError::UnknownVersion(self.descriptor.version))
2439 },
2440 }
2441
2442 let (maybe_core_index_selector, cq_offset) = signals
2444 .core_selector()
2445 .map(|(selector, offset)| (Some(selector), offset))
2446 .unwrap_or_else(|| (None, ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET)));
2447
2448 self.check_core_index(cores_per_para, maybe_core_index_selector, cq_offset)?;
2449
2450 Ok(signals)
2453 }
2454
2455 fn check_core_index(
2459 &self,
2460 cores_per_para: &TransposedClaimQueue,
2461 maybe_core_index_selector: Option<CoreSelector>,
2462 cq_offset: ClaimQueueOffset,
2463 ) -> Result<(), CommittedCandidateReceiptError> {
2464 let assigned_cores = cores_per_para
2465 .get(&self.descriptor.para_id())
2466 .ok_or(CommittedCandidateReceiptError::NoAssignment)?
2467 .get(&cq_offset.0)
2468 .ok_or(CommittedCandidateReceiptError::NoAssignment)?;
2469
2470 if assigned_cores.is_empty() {
2471 return Err(CommittedCandidateReceiptError::NoAssignment);
2472 }
2473
2474 let descriptor_core_index = CoreIndex(self.descriptor.core_index as u32);
2475
2476 let core_index_selector = if let Some(core_index_selector) = maybe_core_index_selector {
2477 core_index_selector
2479 } else if assigned_cores.len() > 1 {
2480 if !assigned_cores.contains(&descriptor_core_index) {
2482 return Err(CommittedCandidateReceiptError::InvalidCoreIndex);
2484 } else {
2485 return Ok(());
2488 }
2489 } else {
2490 CoreSelector(0)
2492 };
2493
2494 let core_index = assigned_cores
2495 .iter()
2496 .nth(core_index_selector.0 as usize % assigned_cores.len())
2497 .ok_or(CommittedCandidateReceiptError::InvalidSelectedCore)
2498 .copied()?;
2499
2500 if core_index != descriptor_core_index {
2501 return Err(CommittedCandidateReceiptError::CoreIndexMismatch {
2502 descriptor: descriptor_core_index,
2503 commitments: core_index,
2504 });
2505 }
2506
2507 Ok(())
2508 }
2509}
2510
2511#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
2513pub struct BackedCandidate<H = Hash> {
2514 candidate: CommittedCandidateReceiptV2<H>,
2516 validity_votes: Vec<ValidityAttestation>,
2518 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
2522}
2523
2524#[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, RuntimeDebug, TypeInfo)]
2526pub struct InherentData<HDR: HeaderT = Header> {
2527 pub bitfields: UncheckedSignedAvailabilityBitfields,
2529 pub backed_candidates: Vec<BackedCandidate<HDR::Hash>>,
2531 pub disputes: MultiDisputeStatementSet,
2533 pub parent_header: HDR,
2535}
2536
2537impl<H> BackedCandidate<H> {
2538 pub fn new(
2540 candidate: CommittedCandidateReceiptV2<H>,
2541 validity_votes: Vec<ValidityAttestation>,
2542 validator_indices: BitVec<u8, bitvec::order::Lsb0>,
2543 core_index: CoreIndex,
2544 ) -> Self {
2545 let mut instance = Self { candidate, validity_votes, validator_indices };
2546 instance.inject_core_index(core_index);
2547 instance
2548 }
2549
2550 pub fn candidate(&self) -> &CommittedCandidateReceiptV2<H> {
2552 &self.candidate
2553 }
2554
2555 #[cfg(feature = "test")]
2558 pub fn candidate_mut(&mut self) -> &mut CommittedCandidateReceiptV2<H> {
2559 &mut self.candidate
2560 }
2561 pub fn descriptor(&self) -> &CandidateDescriptorV2<H> {
2563 &self.candidate.descriptor
2564 }
2565
2566 #[cfg(feature = "test")]
2568 pub fn descriptor_mut(&mut self) -> &mut CandidateDescriptorV2<H> {
2569 &mut self.candidate.descriptor
2570 }
2571
2572 pub fn validity_votes(&self) -> &[ValidityAttestation] {
2574 &self.validity_votes
2575 }
2576
2577 pub fn validity_votes_mut(&mut self) -> &mut Vec<ValidityAttestation> {
2579 &mut self.validity_votes
2580 }
2581
2582 pub fn hash(&self) -> CandidateHash
2584 where
2585 H: Clone + Encode,
2586 {
2587 self.candidate.to_plain().hash()
2588 }
2589
2590 pub fn receipt(&self) -> CandidateReceiptV2<H>
2592 where
2593 H: Clone,
2594 {
2595 self.candidate.to_plain()
2596 }
2597
2598 #[cfg(feature = "test")]
2600 pub fn raw_validator_indices(&self) -> BitVec<u8, bitvec::order::Lsb0> {
2601 self.validator_indices.clone()
2602 }
2603
2604 pub fn validator_indices_and_core_index(
2606 &self,
2607 ) -> (&BitSlice<u8, bitvec::order::Lsb0>, Option<CoreIndex>) {
2608 let core_idx_offset = self.validator_indices.len().saturating_sub(8);
2610 if core_idx_offset > 0 {
2611 let (validator_indices_slice, core_idx_slice) =
2612 self.validator_indices.split_at(core_idx_offset);
2613 return (validator_indices_slice, Some(CoreIndex(core_idx_slice.load::<u8>() as u32)));
2614 }
2615
2616 (&self.validator_indices, None)
2617 }
2618
2619 fn inject_core_index(&mut self, core_index: CoreIndex) {
2621 let core_index_to_inject: BitVec<u8, bitvec::order::Lsb0> =
2622 BitVec::from_vec(vec![core_index.0 as u8]);
2623 self.validator_indices.extend(core_index_to_inject);
2624 }
2625
2626 pub fn set_validator_indices_and_core_index(
2628 &mut self,
2629 new_indices: BitVec<u8, bitvec::order::Lsb0>,
2630 maybe_core_index: Option<CoreIndex>,
2631 ) {
2632 self.validator_indices = new_indices;
2633
2634 if let Some(core_index) = maybe_core_index {
2635 self.inject_core_index(core_index);
2636 }
2637 }
2638}
2639
2640#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
2642#[cfg_attr(feature = "std", derive(PartialEq))]
2643pub struct ScrapedOnChainVotes<H: Encode + Decode = Hash> {
2644 pub session: SessionIndex,
2646 pub backing_validators_per_candidate:
2649 Vec<(CandidateReceiptV2<H>, Vec<(ValidatorIndex, ValidityAttestation)>)>,
2650 pub disputes: MultiDisputeStatementSet,
2654}
2655
2656#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
2658#[cfg_attr(feature = "std", derive(PartialEq))]
2659pub struct OccupiedCore<H = Hash, N = BlockNumber> {
2660 pub next_up_on_available: Option<ScheduledCore>,
2664 pub occupied_since: N,
2666 pub time_out_at: N,
2668 pub next_up_on_time_out: Option<ScheduledCore>,
2672 pub availability: BitVec<u8, bitvec::order::Lsb0>,
2676 pub group_responsible: GroupIndex,
2678 pub candidate_hash: CandidateHash,
2680 pub candidate_descriptor: CandidateDescriptorV2<H>,
2682}
2683
2684impl<H, N> OccupiedCore<H, N> {
2685 pub fn para_id(&self) -> Id {
2687 self.candidate_descriptor.para_id
2688 }
2689}
2690
2691#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
2693#[cfg_attr(feature = "std", derive(PartialEq))]
2694pub enum CoreState<H = Hash, N = BlockNumber> {
2695 #[codec(index = 0)]
2697 Occupied(OccupiedCore<H, N>),
2698 #[codec(index = 1)]
2704 Scheduled(ScheduledCore),
2705 #[codec(index = 2)]
2709 Free,
2710}
2711
2712impl<N> CoreState<N> {
2713 #[deprecated(
2718 note = "`para_id` will be removed. Use `ClaimQueue` to query the scheduled `para_id` instead."
2719 )]
2720 pub fn para_id(&self) -> Option<Id> {
2721 match self {
2722 Self::Occupied(ref core) => core.next_up_on_available.as_ref().map(|n| n.para_id),
2723 Self::Scheduled(core) => Some(core.para_id),
2724 Self::Free => None,
2725 }
2726 }
2727
2728 pub fn is_occupied(&self) -> bool {
2730 matches!(self, Self::Occupied(_))
2731 }
2732}
2733
2734pub type TransposedClaimQueue = BTreeMap<ParaId, BTreeMap<u8, BTreeSet<CoreIndex>>>;
2736
2737pub fn transpose_claim_queue(
2740 claim_queue: BTreeMap<CoreIndex, VecDeque<Id>>,
2741) -> TransposedClaimQueue {
2742 let mut per_para_claim_queue = BTreeMap::new();
2743
2744 for (core, paras) in claim_queue {
2745 for (depth, para) in paras.into_iter().enumerate() {
2747 let depths: &mut BTreeMap<u8, BTreeSet<CoreIndex>> =
2748 per_para_claim_queue.entry(para).or_insert_with(|| Default::default());
2749
2750 depths.entry(depth as u8).or_default().insert(core);
2751 }
2752 }
2753
2754 per_para_claim_queue
2755}
2756
2757#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, DecodeWithMemTracking, TypeInfo, Debug)]
2760pub enum DisputeOffenceKind {
2761 #[codec(index = 0)]
2764 ForInvalidBacked,
2765 #[codec(index = 1)]
2768 AgainstValid,
2769 #[codec(index = 2)]
2772 ForInvalidApproved,
2773}
2774
2775impl From<super::v9::slashing::SlashingOffenceKind> for DisputeOffenceKind {
2779 fn from(value: super::v9::slashing::SlashingOffenceKind) -> Self {
2780 match value {
2781 super::v9::slashing::SlashingOffenceKind::ForInvalid => Self::ForInvalidBacked,
2782 super::v9::slashing::SlashingOffenceKind::AgainstValid => Self::AgainstValid,
2783 }
2784 }
2785}
2786
2787impl TryFrom<DisputeOffenceKind> for super::v9::slashing::SlashingOffenceKind {
2789 type Error = ();
2790
2791 fn try_from(value: DisputeOffenceKind) -> Result<Self, Self::Error> {
2792 match value {
2793 DisputeOffenceKind::ForInvalidBacked => Ok(Self::ForInvalid),
2794 DisputeOffenceKind::AgainstValid => Ok(Self::AgainstValid),
2795 DisputeOffenceKind::ForInvalidApproved => Err(()),
2796 }
2797 }
2798}
2799
2800#[cfg(test)]
2801pub mod tests {
2803 use super::*;
2804
2805 #[test]
2806 fn group_rotation_info_calculations() {
2807 let info =
2808 GroupRotationInfo { session_start_block: 10u32, now: 15, group_rotation_frequency: 5 };
2809
2810 assert_eq!(info.next_rotation_at(), 20);
2811 assert_eq!(info.last_rotation_at(), 15);
2812 }
2813
2814 #[test]
2815 fn group_for_core_is_core_for_group() {
2816 for cores in 1..=256 {
2817 for rotations in 0..(cores * 2) {
2818 let info = GroupRotationInfo {
2819 session_start_block: 0u32,
2820 now: rotations,
2821 group_rotation_frequency: 1,
2822 };
2823
2824 for core in 0..cores {
2825 let group = info.group_for_core(CoreIndex(core), cores as usize);
2826 assert_eq!(info.core_for_group(group, cores as usize).0, core);
2827 }
2828 }
2829 }
2830 }
2831
2832 #[test]
2833 fn test_byzantine_threshold() {
2834 assert_eq!(byzantine_threshold(0), 0);
2835 assert_eq!(byzantine_threshold(1), 0);
2836 assert_eq!(byzantine_threshold(2), 0);
2837 assert_eq!(byzantine_threshold(3), 0);
2838 assert_eq!(byzantine_threshold(4), 1);
2839 assert_eq!(byzantine_threshold(5), 1);
2840 assert_eq!(byzantine_threshold(6), 1);
2841 assert_eq!(byzantine_threshold(7), 2);
2842 }
2843
2844 #[test]
2845 fn test_supermajority_threshold() {
2846 assert_eq!(supermajority_threshold(0), 0);
2847 assert_eq!(supermajority_threshold(1), 1);
2848 assert_eq!(supermajority_threshold(2), 2);
2849 assert_eq!(supermajority_threshold(3), 3);
2850 assert_eq!(supermajority_threshold(4), 3);
2851 assert_eq!(supermajority_threshold(5), 4);
2852 assert_eq!(supermajority_threshold(6), 5);
2853 assert_eq!(supermajority_threshold(7), 5);
2854 }
2855
2856 #[test]
2857 fn balance_bigger_than_usize() {
2858 let zero_b: Balance = 0;
2859 let zero_u: usize = 0;
2860
2861 assert!(zero_b.leading_zeros() >= zero_u.leading_zeros());
2862 }
2863}