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.19.2";
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 StatementWithPVD::Valid(hash) => write!(f, "Valid: {:?}", hash),
247 }
248 }
249}
250
251impl StatementWithPVD {
252 pub fn candidate_hash(&self) -> CandidateHash {
257 match *self {
258 StatementWithPVD::Valid(ref h) => *h,
259 StatementWithPVD::Seconded(ref c, _) => c.hash(),
260 }
261 }
262
263 pub fn to_compact(&self) -> CompactStatement {
266 match *self {
267 StatementWithPVD::Seconded(ref c, _) => CompactStatement::Seconded(c.hash()),
268 StatementWithPVD::Valid(hash) => CompactStatement::Valid(hash),
269 }
270 }
271
272 pub fn drop_pvd(self) -> Statement {
274 match self {
275 StatementWithPVD::Seconded(c, _) => Statement::Seconded(c),
276 StatementWithPVD::Valid(c_h) => Statement::Valid(c_h),
277 }
278 }
279
280 pub fn drop_pvd_from_signed(signed: SignedFullStatementWithPVD) -> SignedFullStatement {
283 signed
284 .convert_to_superpayload_with(|s| s.drop_pvd())
285 .expect("persisted_validation_data doesn't affect encode_as; qed")
286 }
287
288 pub fn signed_to_compact(signed: SignedFullStatementWithPVD) -> Signed<CompactStatement> {
291 signed
292 .convert_to_superpayload_with(|s| s.to_compact())
293 .expect("doesn't affect encode_as; qed")
294 }
295}
296
297impl From<&'_ StatementWithPVD> for CompactStatement {
298 fn from(stmt: &StatementWithPVD) -> Self {
299 stmt.to_compact()
300 }
301}
302
303impl EncodeAs<CompactStatement> for StatementWithPVD {
304 fn encode_as(&self) -> Vec<u8> {
305 self.to_compact().encode()
306 }
307}
308
309pub type SignedFullStatement = Signed<Statement, CompactStatement>;
316
317pub type UncheckedSignedFullStatement = UncheckedSigned<Statement, CompactStatement>;
319
320pub type SignedFullStatementWithPVD = Signed<StatementWithPVD, CompactStatement>;
326
327#[derive(Debug)]
329pub enum InvalidCandidate {
330 ExecutionError(String),
332 InvalidOutputs,
334 Timeout,
336 ParamsTooLarge(u64),
338 CodeTooLarge(u64),
340 PoVDecompressionFailure,
342 BadReturn,
344 BadParent,
346 PoVHashMismatch,
348 BadSignature,
350 ParaHeadHashMismatch,
352 CodeHashMismatch,
354 CommitmentsHashMismatch,
356 InvalidSessionIndex,
358 InvalidUMPSignals(CommittedCandidateReceiptError),
360}
361
362#[derive(Debug)]
364pub enum ValidationResult {
365 Valid(CandidateCommitments, PersistedValidationData),
368 Invalid(InvalidCandidate),
370}
371
372#[derive(PartialEq, Eq, Clone, Encode, Decode, Debug)]
374pub struct PoV {
375 pub block_data: BlockData,
377}
378
379impl PoV {
380 pub fn hash(&self) -> Hash {
382 BlakeTwo256::hash_of(self)
383 }
384}
385
386#[derive(Clone, Encode, Decode)]
388#[cfg(not(target_os = "unknown"))]
389pub enum MaybeCompressedPoV {
390 Raw(PoV),
392 Compressed(PoV),
394}
395
396#[cfg(not(target_os = "unknown"))]
397impl std::fmt::Debug for MaybeCompressedPoV {
398 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
399 let (variant, size) = match self {
400 MaybeCompressedPoV::Raw(pov) => ("Raw", pov.block_data.0.len()),
401 MaybeCompressedPoV::Compressed(pov) => ("Compressed", pov.block_data.0.len()),
402 };
403
404 write!(f, "{} PoV ({} bytes)", variant, size)
405 }
406}
407
408#[cfg(not(target_os = "unknown"))]
409impl MaybeCompressedPoV {
410 pub fn into_compressed(self) -> PoV {
414 match self {
415 Self::Raw(raw) => maybe_compress_pov(raw),
416 Self::Compressed(compressed) => compressed,
417 }
418 }
419}
420
421#[derive(Debug, Clone, Encode, Decode)]
428#[cfg(not(target_os = "unknown"))]
429pub struct Collation<BlockNumber = polkadot_primitives::BlockNumber> {
430 pub upward_messages: UpwardMessages,
432 pub horizontal_messages: HorizontalMessages,
434 pub new_validation_code: Option<ValidationCode>,
436 pub head_data: HeadData,
438 pub proof_of_validity: MaybeCompressedPoV,
440 pub processed_downward_messages: u32,
442 pub hrmp_watermark: BlockNumber,
445}
446
447#[derive(Debug)]
449#[cfg(not(target_os = "unknown"))]
450pub struct CollationSecondedSignal {
451 pub relay_parent: Hash,
453 pub statement: SignedFullStatement,
457}
458
459#[cfg(not(target_os = "unknown"))]
461pub struct CollationResult {
462 pub collation: Collation,
464 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
470}
471
472#[cfg(not(target_os = "unknown"))]
473impl CollationResult {
474 pub fn into_inner(
476 self,
477 ) -> (Collation, Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>) {
478 (self.collation, self.result_sender)
479 }
480}
481
482#[cfg(not(target_os = "unknown"))]
490pub type CollatorFn = Box<
491 dyn Fn(
492 Hash,
493 &PersistedValidationData,
494 ) -> Pin<Box<dyn Future<Output = Option<CollationResult>> + Send>>
495 + Send
496 + Sync,
497>;
498
499#[cfg(not(target_os = "unknown"))]
501pub struct CollationGenerationConfig {
502 pub key: CollatorPair,
504 pub collator: Option<CollatorFn>,
509 pub para_id: ParaId,
511}
512
513#[cfg(not(target_os = "unknown"))]
514impl std::fmt::Debug for CollationGenerationConfig {
515 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
516 write!(f, "CollationGenerationConfig {{ ... }}")
517 }
518}
519
520#[derive(Debug)]
522pub struct SubmitCollationParams {
523 pub relay_parent: Hash,
525 pub collation: Collation,
527 pub parent_head: HeadData,
529 pub validation_code_hash: ValidationCodeHash,
531 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
537 pub core_index: CoreIndex,
539}
540
541#[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)]
543pub struct AvailableData {
544 pub pov: std::sync::Arc<PoV>,
546 pub validation_data: PersistedValidationData,
548}
549
550#[derive(PartialEq, Eq, Clone, Debug, Hash)]
552pub struct Proof(BoundedVec<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, 1, MERKLE_PROOF_MAX_DEPTH>);
553
554impl Proof {
555 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
557 self.0.iter().map(|v| v.as_slice())
558 }
559
560 pub fn dummy_proof() -> Proof {
564 Proof(BoundedVec::from_vec(vec![BoundedVec::from_vec(vec![0]).unwrap()]).unwrap())
565 }
566}
567
568#[derive(thiserror::Error, Debug)]
570pub enum MerkleProofError {
571 #[error("Merkle max proof depth exceeded {0} > {} .", MERKLE_PROOF_MAX_DEPTH)]
572 MerkleProofDepthExceeded(usize),
574
575 #[error("Merkle node max size exceeded {0} > {} .", MERKLE_NODE_MAX_SIZE)]
576 MerkleProofNodeSizeExceeded(usize),
578}
579
580impl TryFrom<Vec<Vec<u8>>> for Proof {
581 type Error = MerkleProofError;
582
583 fn try_from(input: Vec<Vec<u8>>) -> Result<Self, Self::Error> {
584 if input.len() > MERKLE_PROOF_MAX_DEPTH {
585 return Err(Self::Error::MerkleProofDepthExceeded(input.len()))
586 }
587 let mut out = Vec::new();
588 for element in input.into_iter() {
589 let length = element.len();
590 let data: BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE> = BoundedVec::from_vec(element)
591 .map_err(|_| Self::Error::MerkleProofNodeSizeExceeded(length))?;
592 out.push(data);
593 }
594 Ok(Proof(BoundedVec::from_vec(out).expect("Buffer size is deterined above. qed")))
595 }
596}
597
598impl Decode for Proof {
599 fn decode<I: Input>(value: &mut I) -> Result<Self, CodecError> {
600 let temp: Vec<Vec<u8>> = Decode::decode(value)?;
601 let mut out = Vec::new();
602 for element in temp.into_iter() {
603 let bounded_temp: Result<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, CodecError> =
604 BoundedVec::from_vec(element)
605 .map_err(|_| "Inner node exceeds maximum node size.".into());
606 out.push(bounded_temp?);
607 }
608 BoundedVec::from_vec(out)
609 .map(Self)
610 .map_err(|_| "Merkle proof depth exceeds maximum trie depth".into())
611 }
612}
613
614impl Encode for Proof {
615 fn size_hint(&self) -> usize {
616 MERKLE_NODE_MAX_SIZE * MERKLE_PROOF_MAX_DEPTH
617 }
618
619 fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
620 let temp = self.0.iter().map(|v| v.as_vec()).collect::<Vec<_>>();
621 temp.using_encoded(f)
622 }
623}
624
625impl Serialize for Proof {
626 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
627 where
628 S: Serializer,
629 {
630 serializer.serialize_bytes(&self.encode())
631 }
632}
633
634impl<'de> Deserialize<'de> for Proof {
635 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
636 where
637 D: Deserializer<'de>,
638 {
639 let s = Vec::<u8>::deserialize(deserializer)?;
641 let mut slice = s.as_slice();
642 Decode::decode(&mut slice).map_err(de::Error::custom)
643 }
644}
645
646#[derive(PartialEq, Eq, Clone, Encode, Decode, Serialize, Deserialize, Debug, Hash)]
648pub struct ErasureChunk {
649 pub chunk: Vec<u8>,
651 pub index: ChunkIndex,
653 pub proof: Proof,
655}
656
657impl ErasureChunk {
658 pub fn proof(&self) -> &Proof {
660 &self.proof
661 }
662}
663
664#[cfg(not(target_os = "unknown"))]
666pub fn maybe_compress_pov(pov: PoV) -> PoV {
667 let PoV { block_data: BlockData(raw) } = pov;
668 let raw = sp_maybe_compressed_blob::compress(&raw, POV_BOMB_LIMIT).unwrap_or(raw);
669
670 let pov = PoV { block_data: BlockData(raw) };
671 pov
672}