1#![deny(missing_docs)]
24
25use std::{env::var, pin::Pin, sync::LazyLock};
26
27use bounded_vec::BoundedVec;
28use codec::{Decode, Encode, Error as CodecError, Input};
29use futures::Future;
30use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
31
32use polkadot_primitives::{
33 BlakeTwo256, BlockNumber, CandidateCommitments, CandidateDescriptorVersion, CandidateHash,
34 ChunkIndex, CollatorPair, CommittedCandidateReceiptError,
35 CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CompactStatement, CoreIndex,
36 EncodeAs, Hash, HashT, HeadData, Id as ParaId, PersistedValidationData, SessionIndex, Signed,
37 UncheckedSigned, ValidationCode, ValidationCodeHash, MAX_CODE_SIZE, MAX_POV_SIZE,
38};
39pub use sp_consensus_babe::{
40 AllowedSlots as BabeAllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch,
41 Randomness as BabeRandomness,
42};
43use sp_runtime::{self, traits::ConstU32};
44
45pub use polkadot_parachain_primitives::primitives::{
46 BlockData, HorizontalMessages, UpwardMessages,
47};
48
49pub mod approval;
50
51pub mod disputes;
53pub use disputes::{
54 dispute_is_inactive, CandidateVotes, DisputeMessage, DisputeMessageCheckError, DisputeStatus,
55 InvalidDisputeVote, SignedDisputeStatement, Timestamp, UncheckedDisputeMessage,
56 ValidDisputeVote, ACTIVE_DURATION_SECS,
57};
58
59pub const NODE_VERSION: &'static str = "1.24.1";
65
66const MERKLE_NODE_MAX_SIZE: usize = 512 + 100;
70const MERKLE_PROOF_MAX_DEPTH: usize = 8;
72
73pub const MAX_SEGMENT_LEN: u32 = 32;
78
79#[deprecated(
81 note = "`VALIDATION_CODE_BOMB_LIMIT` will be removed. Use `validation_code_bomb_limit`
82 runtime API to retrieve the value from the runtime"
83)]
84pub const VALIDATION_CODE_BOMB_LIMIT: usize = (MAX_CODE_SIZE * 4u32) as usize;
85
86pub const POV_BOMB_LIMIT: usize = (MAX_POV_SIZE * 4u32) as usize;
88
89pub static DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION: LazyLock<BlockNumber> =
115 LazyLock::new(|| {
116 if var("ZOMBIE_DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION").is_ok() {
117 1
118 } else {
119 10
120 }
121 });
122
123pub const MAX_FINALITY_LAG: u32 = 500;
127
128#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
135pub struct SessionWindowSize(SessionIndex);
136
137#[macro_export]
138macro_rules! new_session_window_size {
140 (0) => {
141 compile_error!("Must be non zero");
142 };
143 (0_u32) => {
144 compile_error!("Must be non zero");
145 };
146 (0 as u32) => {
147 compile_error!("Must be non zero");
148 };
149 (0 as _) => {
150 compile_error!("Must be non zero");
151 };
152 ($l:literal) => {
153 SessionWindowSize::unchecked_new($l as _)
154 };
155}
156
157pub const DISPUTE_WINDOW: SessionWindowSize = new_session_window_size!(6);
162
163impl SessionWindowSize {
164 pub fn get(self) -> SessionIndex {
166 self.0
167 }
168
169 #[doc(hidden)]
174 pub const fn unchecked_new(size: SessionIndex) -> Self {
175 Self(size)
176 }
177}
178
179pub type BlockWeight = u32;
181
182#[derive(Clone, PartialEq, Eq, Encode, Decode)]
189pub enum Statement {
190 #[codec(index = 1)]
192 Seconded(CommittedCandidateReceipt),
193 #[codec(index = 2)]
195 Valid(CandidateHash),
196}
197
198impl std::fmt::Debug for Statement {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 match self {
201 Statement::Seconded(seconded) => write!(f, "Seconded: {:?}", seconded.descriptor),
202 Statement::Valid(hash) => write!(f, "Valid: {:?}", hash),
203 }
204 }
205}
206
207impl Statement {
208 pub fn candidate_hash(&self) -> CandidateHash {
213 match *self {
214 Statement::Valid(ref h) => *h,
215 Statement::Seconded(ref c) => c.hash(),
216 }
217 }
218
219 pub fn to_compact(&self) -> CompactStatement {
222 match *self {
223 Statement::Seconded(ref c) => CompactStatement::Seconded(c.hash()),
224 Statement::Valid(hash) => CompactStatement::Valid(hash),
225 }
226 }
227
228 pub fn supply_pvd(self, pvd: PersistedValidationData) -> StatementWithPVD {
230 match self {
231 Statement::Seconded(c) => StatementWithPVD::Seconded(c, pvd),
232 Statement::Valid(hash) => StatementWithPVD::Valid(hash),
233 }
234 }
235}
236
237impl From<&'_ Statement> for CompactStatement {
238 fn from(stmt: &Statement) -> Self {
239 stmt.to_compact()
240 }
241}
242
243impl EncodeAs<CompactStatement> for Statement {
244 fn encode_as(&self) -> Vec<u8> {
245 self.to_compact().encode()
246 }
247}
248
249#[derive(Clone, PartialEq, Eq)]
252pub enum StatementWithPVD {
253 Seconded(CommittedCandidateReceipt, PersistedValidationData),
255 Valid(CandidateHash),
257}
258
259impl std::fmt::Debug for StatementWithPVD {
260 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
261 match self {
262 StatementWithPVD::Seconded(seconded, _) => {
263 write!(f, "Seconded: {:?}", seconded.descriptor)
264 },
265 StatementWithPVD::Valid(hash) => write!(f, "Valid: {:?}", hash),
266 }
267 }
268}
269
270impl StatementWithPVD {
271 pub fn candidate_hash(&self) -> CandidateHash {
276 match *self {
277 StatementWithPVD::Valid(ref h) => *h,
278 StatementWithPVD::Seconded(ref c, _) => c.hash(),
279 }
280 }
281
282 pub fn to_compact(&self) -> CompactStatement {
285 match *self {
286 StatementWithPVD::Seconded(ref c, _) => CompactStatement::Seconded(c.hash()),
287 StatementWithPVD::Valid(hash) => CompactStatement::Valid(hash),
288 }
289 }
290
291 pub fn drop_pvd(self) -> Statement {
293 match self {
294 StatementWithPVD::Seconded(c, _) => Statement::Seconded(c),
295 StatementWithPVD::Valid(c_h) => Statement::Valid(c_h),
296 }
297 }
298
299 pub fn drop_pvd_from_signed(signed: SignedFullStatementWithPVD) -> SignedFullStatement {
302 signed
303 .convert_to_superpayload_with(|s| s.drop_pvd())
304 .expect("persisted_validation_data doesn't affect encode_as; qed")
305 }
306
307 pub fn signed_to_compact(signed: SignedFullStatementWithPVD) -> Signed<CompactStatement> {
310 signed
311 .convert_to_superpayload_with(|s| s.to_compact())
312 .expect("doesn't affect encode_as; qed")
313 }
314}
315
316impl From<&'_ StatementWithPVD> for CompactStatement {
317 fn from(stmt: &StatementWithPVD) -> Self {
318 stmt.to_compact()
319 }
320}
321
322impl EncodeAs<CompactStatement> for StatementWithPVD {
323 fn encode_as(&self) -> Vec<u8> {
324 self.to_compact().encode()
325 }
326}
327
328pub type SignedFullStatement = Signed<Statement, CompactStatement>;
335
336pub type UncheckedSignedFullStatement = UncheckedSigned<Statement, CompactStatement>;
338
339pub type SignedFullStatementWithPVD = Signed<StatementWithPVD, CompactStatement>;
345
346#[derive(Debug)]
348pub enum InvalidCandidate {
349 ExecutionError(String),
351 InvalidOutputs,
353 Timeout,
355 ParamsTooLarge(u64),
357 CodeTooLarge(u64),
359 PoVDecompressionFailure,
361 BadReturn,
363 BadParent,
365 PoVHashMismatch,
367 BadSignature,
369 ParaHeadHashMismatch,
371 CodeHashMismatch,
373 CommitmentsHashMismatch,
375 InvalidSchedulingSession,
377 InvalidRelayParentSession,
379 InvalidUMPSignals(CommittedCandidateReceiptError),
381}
382
383#[derive(Debug)]
385pub enum ValidationResult {
386 Valid(CandidateCommitments, PersistedValidationData),
389 Invalid(InvalidCandidate),
391}
392
393#[derive(PartialEq, Eq, Clone, Encode, Decode, Debug)]
395pub struct PoV {
396 pub block_data: BlockData,
398}
399
400impl PoV {
401 pub fn hash(&self) -> Hash {
403 BlakeTwo256::hash_of(self)
404 }
405}
406
407#[derive(Clone, Encode, Decode)]
409#[cfg(not(target_os = "unknown"))]
410pub enum MaybeCompressedPoV {
411 Raw(PoV),
413 Compressed(PoV),
415}
416
417#[cfg(not(target_os = "unknown"))]
418impl std::fmt::Debug for MaybeCompressedPoV {
419 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
420 let (variant, size) = match self {
421 MaybeCompressedPoV::Raw(pov) => ("Raw", pov.block_data.0.len()),
422 MaybeCompressedPoV::Compressed(pov) => ("Compressed", pov.block_data.0.len()),
423 };
424
425 write!(f, "{} PoV ({} bytes)", variant, size)
426 }
427}
428
429#[cfg(not(target_os = "unknown"))]
430impl MaybeCompressedPoV {
431 pub fn into_compressed(self) -> PoV {
435 match self {
436 Self::Raw(raw) => maybe_compress_pov(raw),
437 Self::Compressed(compressed) => compressed,
438 }
439 }
440}
441
442#[derive(Debug, Clone, Encode, Decode)]
449#[cfg(not(target_os = "unknown"))]
450pub struct Collation<BlockNumber = polkadot_primitives::BlockNumber> {
451 pub upward_messages: UpwardMessages,
453 pub horizontal_messages: HorizontalMessages,
455 pub new_validation_code: Option<ValidationCode>,
457 pub head_data: HeadData,
459 pub proof_of_validity: MaybeCompressedPoV,
461 pub processed_downward_messages: u32,
463 pub hrmp_watermark: BlockNumber,
466}
467
468#[cfg(not(target_os = "unknown"))]
470pub struct CollationResult {
471 pub collation: Collation,
473}
474
475#[cfg(not(target_os = "unknown"))]
483pub type CollatorFn = Box<
484 dyn Fn(
485 Hash,
486 &PersistedValidationData,
487 ) -> Pin<Box<dyn Future<Output = Option<CollationResult>> + Send>>
488 + Send
489 + Sync,
490>;
491
492#[cfg(not(target_os = "unknown"))]
494pub struct CollationGenerationConfig {
495 pub key: CollatorPair,
497 pub collator: Option<CollatorFn>,
502 pub para_id: ParaId,
504}
505
506#[cfg(not(target_os = "unknown"))]
507impl std::fmt::Debug for CollationGenerationConfig {
508 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
509 write!(f, "CollationGenerationConfig {{ ... }}")
510 }
511}
512
513#[derive(Debug)]
515pub struct SegmentCollation {
516 pub collation: Collation,
518 pub relay_parent: Hash,
520 pub validation_data: PersistedValidationData,
523 pub validation_code_hash: ValidationCodeHash,
525 pub session_index: SessionIndex,
528}
529
530#[derive(Debug)]
536pub struct SubmitSegmentParams {
537 pub scheduling_parent: Hash,
542 pub core_index: CoreIndex,
544 pub candidates_descriptor_version: CandidateDescriptorVersion,
546 pub collations: sp_runtime::BoundedVec<SegmentCollation, ConstU32<MAX_SEGMENT_LEN>>,
548}
549
550#[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)]
552pub struct AvailableData {
553 pub pov: std::sync::Arc<PoV>,
555 pub validation_data: PersistedValidationData,
557}
558
559#[derive(PartialEq, Eq, Clone, Debug, Hash)]
561pub struct Proof(BoundedVec<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, 1, MERKLE_PROOF_MAX_DEPTH>);
562
563impl Proof {
564 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
566 self.0.iter().map(|v| v.as_slice())
567 }
568
569 pub fn dummy_proof() -> Proof {
573 Proof(BoundedVec::from_vec(vec![BoundedVec::from_vec(vec![0]).unwrap()]).unwrap())
574 }
575}
576
577#[derive(thiserror::Error, Debug)]
579pub enum MerkleProofError {
580 #[error("Merkle max proof depth exceeded {0} > {} .", MERKLE_PROOF_MAX_DEPTH)]
581 MerkleProofDepthExceeded(usize),
583
584 #[error("Merkle node max size exceeded {0} > {} .", MERKLE_NODE_MAX_SIZE)]
585 MerkleProofNodeSizeExceeded(usize),
587}
588
589impl TryFrom<Vec<Vec<u8>>> for Proof {
590 type Error = MerkleProofError;
591
592 fn try_from(input: Vec<Vec<u8>>) -> Result<Self, Self::Error> {
593 if input.len() > MERKLE_PROOF_MAX_DEPTH {
594 return Err(Self::Error::MerkleProofDepthExceeded(input.len()));
595 }
596 let mut out = Vec::new();
597 for element in input.into_iter() {
598 let length = element.len();
599 let data: BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE> = BoundedVec::from_vec(element)
600 .map_err(|_| Self::Error::MerkleProofNodeSizeExceeded(length))?;
601 out.push(data);
602 }
603 Ok(Proof(BoundedVec::from_vec(out).expect("Buffer size is deterined above. qed")))
604 }
605}
606
607impl Decode for Proof {
608 fn decode<I: Input>(value: &mut I) -> Result<Self, CodecError> {
609 let temp: Vec<Vec<u8>> = Decode::decode(value)?;
610 let mut out = Vec::new();
611 for element in temp.into_iter() {
612 let bounded_temp: Result<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, CodecError> =
613 BoundedVec::from_vec(element)
614 .map_err(|_| "Inner node exceeds maximum node size.".into());
615 out.push(bounded_temp?);
616 }
617 BoundedVec::from_vec(out)
618 .map(Self)
619 .map_err(|_| "Merkle proof depth exceeds maximum trie depth".into())
620 }
621}
622
623impl Encode for Proof {
624 fn size_hint(&self) -> usize {
625 MERKLE_NODE_MAX_SIZE * MERKLE_PROOF_MAX_DEPTH
626 }
627
628 fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
629 let temp = self.0.iter().map(|v| v.as_vec()).collect::<Vec<_>>();
630 temp.using_encoded(f)
631 }
632}
633
634impl Serialize for Proof {
635 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
636 where
637 S: Serializer,
638 {
639 serializer.serialize_bytes(&self.encode())
640 }
641}
642
643impl<'de> Deserialize<'de> for Proof {
644 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
645 where
646 D: Deserializer<'de>,
647 {
648 let s = Vec::<u8>::deserialize(deserializer)?;
650 let mut slice = s.as_slice();
651 Decode::decode(&mut slice).map_err(de::Error::custom)
652 }
653}
654
655#[derive(PartialEq, Eq, Clone, Encode, Decode, Serialize, Deserialize, Debug, Hash)]
657pub struct ErasureChunk {
658 pub chunk: Vec<u8>,
660 pub index: ChunkIndex,
662 pub proof: Proof,
664}
665
666impl ErasureChunk {
667 pub fn proof(&self) -> &Proof {
669 &self.proof
670 }
671}
672
673#[cfg(not(target_os = "unknown"))]
675pub fn maybe_compress_pov(pov: PoV) -> PoV {
676 let PoV { block_data: BlockData(raw) } = pov;
677 let raw = sp_maybe_compressed_blob::compress_weakly(&raw, POV_BOMB_LIMIT).unwrap_or(raw);
678
679 let pov = PoV { block_data: BlockData(raw) };
680 pov
681}