1#![deny(missing_docs)]
24
25use std::pin::Pin;
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, CandidateHash, ChunkIndex, CollatorPair,
34 CommittedCandidateReceiptError, CommittedCandidateReceiptV2 as CommittedCandidateReceipt,
35 CompactStatement, CoreIndex, EncodeAs, Hash, HashT, HeadData, Id as ParaId,
36 PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode,
37 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};
43
44pub use polkadot_parachain_primitives::primitives::{
45 BlockData, HorizontalMessages, UpwardMessages,
46};
47
48pub mod approval;
49
50pub mod disputes;
52pub use disputes::{
53 dispute_is_inactive, CandidateVotes, DisputeMessage, DisputeMessageCheckError, DisputeStatus,
54 InvalidDisputeVote, SignedDisputeStatement, Timestamp, UncheckedDisputeMessage,
55 ValidDisputeVote, ACTIVE_DURATION_SECS,
56};
57
58pub const NODE_VERSION: &'static str = "1.22.3";
64
65const MERKLE_NODE_MAX_SIZE: usize = 512 + 100;
69const MERKLE_PROOF_MAX_DEPTH: usize = 8;
71
72#[deprecated(
74 note = "`VALIDATION_CODE_BOMB_LIMIT` will be removed. Use `validation_code_bomb_limit`
75 runtime API to retrieve the value from the runtime"
76)]
77pub const VALIDATION_CODE_BOMB_LIMIT: usize = (MAX_CODE_SIZE * 4u32) as usize;
78
79pub const POV_BOMB_LIMIT: usize = (MAX_POV_SIZE * 4u32) as usize;
81
82pub const DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION: BlockNumber = 10;
104
105pub const MAX_FINALITY_LAG: u32 = 500;
109
110#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
117pub struct SessionWindowSize(SessionIndex);
118
119#[macro_export]
120macro_rules! new_session_window_size {
122 (0) => {
123 compile_error!("Must be non zero");
124 };
125 (0_u32) => {
126 compile_error!("Must be non zero");
127 };
128 (0 as u32) => {
129 compile_error!("Must be non zero");
130 };
131 (0 as _) => {
132 compile_error!("Must be non zero");
133 };
134 ($l:literal) => {
135 SessionWindowSize::unchecked_new($l as _)
136 };
137}
138
139pub const DISPUTE_WINDOW: SessionWindowSize = new_session_window_size!(6);
144
145impl SessionWindowSize {
146 pub fn get(self) -> SessionIndex {
148 self.0
149 }
150
151 #[doc(hidden)]
156 pub const fn unchecked_new(size: SessionIndex) -> Self {
157 Self(size)
158 }
159}
160
161pub type BlockWeight = u32;
163
164#[derive(Clone, PartialEq, Eq, Encode, Decode)]
171pub enum Statement {
172 #[codec(index = 1)]
174 Seconded(CommittedCandidateReceipt),
175 #[codec(index = 2)]
177 Valid(CandidateHash),
178}
179
180impl std::fmt::Debug for Statement {
181 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182 match self {
183 Statement::Seconded(seconded) => write!(f, "Seconded: {:?}", seconded.descriptor),
184 Statement::Valid(hash) => write!(f, "Valid: {:?}", hash),
185 }
186 }
187}
188
189impl Statement {
190 pub fn candidate_hash(&self) -> CandidateHash {
195 match *self {
196 Statement::Valid(ref h) => *h,
197 Statement::Seconded(ref c) => c.hash(),
198 }
199 }
200
201 pub fn to_compact(&self) -> CompactStatement {
204 match *self {
205 Statement::Seconded(ref c) => CompactStatement::Seconded(c.hash()),
206 Statement::Valid(hash) => CompactStatement::Valid(hash),
207 }
208 }
209
210 pub fn supply_pvd(self, pvd: PersistedValidationData) -> StatementWithPVD {
212 match self {
213 Statement::Seconded(c) => StatementWithPVD::Seconded(c, pvd),
214 Statement::Valid(hash) => StatementWithPVD::Valid(hash),
215 }
216 }
217}
218
219impl From<&'_ Statement> for CompactStatement {
220 fn from(stmt: &Statement) -> Self {
221 stmt.to_compact()
222 }
223}
224
225impl EncodeAs<CompactStatement> for Statement {
226 fn encode_as(&self) -> Vec<u8> {
227 self.to_compact().encode()
228 }
229}
230
231#[derive(Clone, PartialEq, Eq)]
234pub enum StatementWithPVD {
235 Seconded(CommittedCandidateReceipt, PersistedValidationData),
237 Valid(CandidateHash),
239}
240
241impl std::fmt::Debug for StatementWithPVD {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 match self {
244 StatementWithPVD::Seconded(seconded, _) => {
245 write!(f, "Seconded: {:?}", seconded.descriptor)
246 },
247 StatementWithPVD::Valid(hash) => write!(f, "Valid: {:?}", hash),
248 }
249 }
250}
251
252impl StatementWithPVD {
253 pub fn candidate_hash(&self) -> CandidateHash {
258 match *self {
259 StatementWithPVD::Valid(ref h) => *h,
260 StatementWithPVD::Seconded(ref c, _) => c.hash(),
261 }
262 }
263
264 pub fn to_compact(&self) -> CompactStatement {
267 match *self {
268 StatementWithPVD::Seconded(ref c, _) => CompactStatement::Seconded(c.hash()),
269 StatementWithPVD::Valid(hash) => CompactStatement::Valid(hash),
270 }
271 }
272
273 pub fn drop_pvd(self) -> Statement {
275 match self {
276 StatementWithPVD::Seconded(c, _) => Statement::Seconded(c),
277 StatementWithPVD::Valid(c_h) => Statement::Valid(c_h),
278 }
279 }
280
281 pub fn drop_pvd_from_signed(signed: SignedFullStatementWithPVD) -> SignedFullStatement {
284 signed
285 .convert_to_superpayload_with(|s| s.drop_pvd())
286 .expect("persisted_validation_data doesn't affect encode_as; qed")
287 }
288
289 pub fn signed_to_compact(signed: SignedFullStatementWithPVD) -> Signed<CompactStatement> {
292 signed
293 .convert_to_superpayload_with(|s| s.to_compact())
294 .expect("doesn't affect encode_as; qed")
295 }
296}
297
298impl From<&'_ StatementWithPVD> for CompactStatement {
299 fn from(stmt: &StatementWithPVD) -> Self {
300 stmt.to_compact()
301 }
302}
303
304impl EncodeAs<CompactStatement> for StatementWithPVD {
305 fn encode_as(&self) -> Vec<u8> {
306 self.to_compact().encode()
307 }
308}
309
310pub type SignedFullStatement = Signed<Statement, CompactStatement>;
317
318pub type UncheckedSignedFullStatement = UncheckedSigned<Statement, CompactStatement>;
320
321pub type SignedFullStatementWithPVD = Signed<StatementWithPVD, CompactStatement>;
327
328#[derive(Debug)]
330pub enum InvalidCandidate {
331 ExecutionError(String),
333 InvalidOutputs,
335 Timeout,
337 ParamsTooLarge(u64),
339 CodeTooLarge(u64),
341 PoVDecompressionFailure,
343 BadReturn,
345 BadParent,
347 PoVHashMismatch,
349 BadSignature,
351 ParaHeadHashMismatch,
353 CodeHashMismatch,
355 CommitmentsHashMismatch,
357 InvalidSchedulingSession,
359 InvalidRelayParentSession,
361 InvalidUMPSignals(CommittedCandidateReceiptError),
363}
364
365#[derive(Debug)]
367pub enum ValidationResult {
368 Valid(CandidateCommitments, PersistedValidationData),
371 Invalid(InvalidCandidate),
373}
374
375#[derive(PartialEq, Eq, Clone, Encode, Decode, Debug)]
377pub struct PoV {
378 pub block_data: BlockData,
380}
381
382impl PoV {
383 pub fn hash(&self) -> Hash {
385 BlakeTwo256::hash_of(self)
386 }
387}
388
389#[derive(Clone, Encode, Decode)]
391#[cfg(not(target_os = "unknown"))]
392pub enum MaybeCompressedPoV {
393 Raw(PoV),
395 Compressed(PoV),
397}
398
399#[cfg(not(target_os = "unknown"))]
400impl std::fmt::Debug for MaybeCompressedPoV {
401 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
402 let (variant, size) = match self {
403 MaybeCompressedPoV::Raw(pov) => ("Raw", pov.block_data.0.len()),
404 MaybeCompressedPoV::Compressed(pov) => ("Compressed", pov.block_data.0.len()),
405 };
406
407 write!(f, "{} PoV ({} bytes)", variant, size)
408 }
409}
410
411#[cfg(not(target_os = "unknown"))]
412impl MaybeCompressedPoV {
413 pub fn into_compressed(self) -> PoV {
417 match self {
418 Self::Raw(raw) => maybe_compress_pov(raw),
419 Self::Compressed(compressed) => compressed,
420 }
421 }
422}
423
424#[derive(Debug, Clone, Encode, Decode)]
431#[cfg(not(target_os = "unknown"))]
432pub struct Collation<BlockNumber = polkadot_primitives::BlockNumber> {
433 pub upward_messages: UpwardMessages,
435 pub horizontal_messages: HorizontalMessages,
437 pub new_validation_code: Option<ValidationCode>,
439 pub head_data: HeadData,
441 pub proof_of_validity: MaybeCompressedPoV,
443 pub processed_downward_messages: u32,
445 pub hrmp_watermark: BlockNumber,
448}
449
450#[derive(Debug)]
452#[cfg(not(target_os = "unknown"))]
453pub struct CollationSecondedSignal {
454 pub scheduling_parent: Hash,
458 pub statement: SignedFullStatement,
462}
463
464#[cfg(not(target_os = "unknown"))]
466pub struct CollationResult {
467 pub collation: Collation,
469 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
475}
476
477#[cfg(not(target_os = "unknown"))]
478impl CollationResult {
479 pub fn into_inner(
481 self,
482 ) -> (Collation, Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>) {
483 (self.collation, self.result_sender)
484 }
485}
486
487#[cfg(not(target_os = "unknown"))]
495pub type CollatorFn = Box<
496 dyn Fn(
497 Hash,
498 &PersistedValidationData,
499 ) -> Pin<Box<dyn Future<Output = Option<CollationResult>> + Send>>
500 + Send
501 + Sync,
502>;
503
504#[cfg(not(target_os = "unknown"))]
506pub struct CollationGenerationConfig {
507 pub key: CollatorPair,
509 pub collator: Option<CollatorFn>,
514 pub para_id: ParaId,
516}
517
518#[cfg(not(target_os = "unknown"))]
519impl std::fmt::Debug for CollationGenerationConfig {
520 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
521 write!(f, "CollationGenerationConfig {{ ... }}")
522 }
523}
524
525#[derive(Debug)]
527pub struct SubmitCollationParams {
528 pub relay_parent: Hash,
530 pub collation: Collation,
532 pub validation_code_hash: ValidationCodeHash,
534 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
540 pub core_index: CoreIndex,
542 pub scheduling_parent: Option<Hash>,
548 pub session_index: SessionIndex,
551 pub validation_data: PersistedValidationData,
554}
555
556#[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)]
558pub struct AvailableData {
559 pub pov: std::sync::Arc<PoV>,
561 pub validation_data: PersistedValidationData,
563}
564
565#[derive(PartialEq, Eq, Clone, Debug, Hash)]
567pub struct Proof(BoundedVec<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, 1, MERKLE_PROOF_MAX_DEPTH>);
568
569impl Proof {
570 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
572 self.0.iter().map(|v| v.as_slice())
573 }
574
575 pub fn dummy_proof() -> Proof {
579 Proof(BoundedVec::from_vec(vec![BoundedVec::from_vec(vec![0]).unwrap()]).unwrap())
580 }
581}
582
583#[derive(thiserror::Error, Debug)]
585pub enum MerkleProofError {
586 #[error("Merkle max proof depth exceeded {0} > {} .", MERKLE_PROOF_MAX_DEPTH)]
587 MerkleProofDepthExceeded(usize),
589
590 #[error("Merkle node max size exceeded {0} > {} .", MERKLE_NODE_MAX_SIZE)]
591 MerkleProofNodeSizeExceeded(usize),
593}
594
595impl TryFrom<Vec<Vec<u8>>> for Proof {
596 type Error = MerkleProofError;
597
598 fn try_from(input: Vec<Vec<u8>>) -> Result<Self, Self::Error> {
599 if input.len() > MERKLE_PROOF_MAX_DEPTH {
600 return Err(Self::Error::MerkleProofDepthExceeded(input.len()));
601 }
602 let mut out = Vec::new();
603 for element in input.into_iter() {
604 let length = element.len();
605 let data: BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE> = BoundedVec::from_vec(element)
606 .map_err(|_| Self::Error::MerkleProofNodeSizeExceeded(length))?;
607 out.push(data);
608 }
609 Ok(Proof(BoundedVec::from_vec(out).expect("Buffer size is deterined above. qed")))
610 }
611}
612
613impl Decode for Proof {
614 fn decode<I: Input>(value: &mut I) -> Result<Self, CodecError> {
615 let temp: Vec<Vec<u8>> = Decode::decode(value)?;
616 let mut out = Vec::new();
617 for element in temp.into_iter() {
618 let bounded_temp: Result<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, CodecError> =
619 BoundedVec::from_vec(element)
620 .map_err(|_| "Inner node exceeds maximum node size.".into());
621 out.push(bounded_temp?);
622 }
623 BoundedVec::from_vec(out)
624 .map(Self)
625 .map_err(|_| "Merkle proof depth exceeds maximum trie depth".into())
626 }
627}
628
629impl Encode for Proof {
630 fn size_hint(&self) -> usize {
631 MERKLE_NODE_MAX_SIZE * MERKLE_PROOF_MAX_DEPTH
632 }
633
634 fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
635 let temp = self.0.iter().map(|v| v.as_vec()).collect::<Vec<_>>();
636 temp.using_encoded(f)
637 }
638}
639
640impl Serialize for Proof {
641 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
642 where
643 S: Serializer,
644 {
645 serializer.serialize_bytes(&self.encode())
646 }
647}
648
649impl<'de> Deserialize<'de> for Proof {
650 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
651 where
652 D: Deserializer<'de>,
653 {
654 let s = Vec::<u8>::deserialize(deserializer)?;
656 let mut slice = s.as_slice();
657 Decode::decode(&mut slice).map_err(de::Error::custom)
658 }
659}
660
661#[derive(PartialEq, Eq, Clone, Encode, Decode, Serialize, Deserialize, Debug, Hash)]
663pub struct ErasureChunk {
664 pub chunk: Vec<u8>,
666 pub index: ChunkIndex,
668 pub proof: Proof,
670}
671
672impl ErasureChunk {
673 pub fn proof(&self) -> &Proof {
675 &self.proof
676 }
677}
678
679#[cfg(not(target_os = "unknown"))]
681pub fn maybe_compress_pov(pov: PoV) -> PoV {
682 let PoV { block_data: BlockData(raw) } = pov;
683 let raw = sp_maybe_compressed_blob::compress_weakly(&raw, POV_BOMB_LIMIT).unwrap_or(raw);
684
685 let pov = PoV { block_data: BlockData(raw) };
686 pov
687}