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 vstaging::{
34 CommittedCandidateReceiptError, CommittedCandidateReceiptV2 as CommittedCandidateReceipt,
35 },
36 BlakeTwo256, BlockNumber, CandidateCommitments, CandidateHash, ChunkIndex, CollatorPair,
37 CompactStatement, CoreIndex, EncodeAs, Hash, HashT, HeadData, Id as ParaId,
38 PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode,
39 ValidationCodeHash, MAX_CODE_SIZE, MAX_POV_SIZE,
40};
41pub use sp_consensus_babe::{
42 AllowedSlots as BabeAllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch,
43 Randomness as BabeRandomness,
44};
45
46pub use polkadot_parachain_primitives::primitives::{
47 BlockData, HorizontalMessages, UpwardMessages,
48};
49
50pub mod approval;
51
52pub mod disputes;
54pub use disputes::{
55 dispute_is_inactive, CandidateVotes, DisputeMessage, DisputeMessageCheckError, DisputeStatus,
56 InvalidDisputeVote, SignedDisputeStatement, Timestamp, UncheckedDisputeMessage,
57 ValidDisputeVote, ACTIVE_DURATION_SECS,
58};
59
60pub const NODE_VERSION: &'static str = "1.20.0";
66
67const MERKLE_NODE_MAX_SIZE: usize = 512 + 100;
71const MERKLE_PROOF_MAX_DEPTH: usize = 8;
73
74#[deprecated(
76 note = "`VALIDATION_CODE_BOMB_LIMIT` will be removed. Use `validation_code_bomb_limit`
77 runtime API to retrieve the value from the runtime"
78)]
79pub const VALIDATION_CODE_BOMB_LIMIT: usize = (MAX_CODE_SIZE * 4u32) as usize;
80
81pub const POV_BOMB_LIMIT: usize = (MAX_POV_SIZE * 4u32) as usize;
83
84pub const DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION: BlockNumber = 10;
106
107pub const MAX_FINALITY_LAG: u32 = 500;
111
112#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
119pub struct SessionWindowSize(SessionIndex);
120
121#[macro_export]
122macro_rules! new_session_window_size {
124 (0) => {
125 compile_error!("Must be non zero");
126 };
127 (0_u32) => {
128 compile_error!("Must be non zero");
129 };
130 (0 as u32) => {
131 compile_error!("Must be non zero");
132 };
133 (0 as _) => {
134 compile_error!("Must be non zero");
135 };
136 ($l:literal) => {
137 SessionWindowSize::unchecked_new($l as _)
138 };
139}
140
141pub const DISPUTE_WINDOW: SessionWindowSize = new_session_window_size!(6);
146
147impl SessionWindowSize {
148 pub fn get(self) -> SessionIndex {
150 self.0
151 }
152
153 #[doc(hidden)]
158 pub const fn unchecked_new(size: SessionIndex) -> Self {
159 Self(size)
160 }
161}
162
163pub type BlockWeight = u32;
165
166#[derive(Clone, PartialEq, Eq, Encode, Decode)]
173pub enum Statement {
174 #[codec(index = 1)]
176 Seconded(CommittedCandidateReceipt),
177 #[codec(index = 2)]
179 Valid(CandidateHash),
180}
181
182impl std::fmt::Debug for Statement {
183 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 match self {
185 Statement::Seconded(seconded) => write!(f, "Seconded: {:?}", seconded.descriptor),
186 Statement::Valid(hash) => write!(f, "Valid: {:?}", hash),
187 }
188 }
189}
190
191impl Statement {
192 pub fn candidate_hash(&self) -> CandidateHash {
197 match *self {
198 Statement::Valid(ref h) => *h,
199 Statement::Seconded(ref c) => c.hash(),
200 }
201 }
202
203 pub fn to_compact(&self) -> CompactStatement {
206 match *self {
207 Statement::Seconded(ref c) => CompactStatement::Seconded(c.hash()),
208 Statement::Valid(hash) => CompactStatement::Valid(hash),
209 }
210 }
211
212 pub fn supply_pvd(self, pvd: PersistedValidationData) -> StatementWithPVD {
214 match self {
215 Statement::Seconded(c) => StatementWithPVD::Seconded(c, pvd),
216 Statement::Valid(hash) => StatementWithPVD::Valid(hash),
217 }
218 }
219}
220
221impl From<&'_ Statement> for CompactStatement {
222 fn from(stmt: &Statement) -> Self {
223 stmt.to_compact()
224 }
225}
226
227impl EncodeAs<CompactStatement> for Statement {
228 fn encode_as(&self) -> Vec<u8> {
229 self.to_compact().encode()
230 }
231}
232
233#[derive(Clone, PartialEq, Eq)]
236pub enum StatementWithPVD {
237 Seconded(CommittedCandidateReceipt, PersistedValidationData),
239 Valid(CandidateHash),
241}
242
243impl std::fmt::Debug for StatementWithPVD {
244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 match self {
246 StatementWithPVD::Seconded(seconded, _) =>
247 write!(f, "Seconded: {:?}", seconded.descriptor),
248 StatementWithPVD::Valid(hash) => write!(f, "Valid: {:?}", hash),
249 }
250 }
251}
252
253impl StatementWithPVD {
254 pub fn candidate_hash(&self) -> CandidateHash {
259 match *self {
260 StatementWithPVD::Valid(ref h) => *h,
261 StatementWithPVD::Seconded(ref c, _) => c.hash(),
262 }
263 }
264
265 pub fn to_compact(&self) -> CompactStatement {
268 match *self {
269 StatementWithPVD::Seconded(ref c, _) => CompactStatement::Seconded(c.hash()),
270 StatementWithPVD::Valid(hash) => CompactStatement::Valid(hash),
271 }
272 }
273
274 pub fn drop_pvd(self) -> Statement {
276 match self {
277 StatementWithPVD::Seconded(c, _) => Statement::Seconded(c),
278 StatementWithPVD::Valid(c_h) => Statement::Valid(c_h),
279 }
280 }
281
282 pub fn drop_pvd_from_signed(signed: SignedFullStatementWithPVD) -> SignedFullStatement {
285 signed
286 .convert_to_superpayload_with(|s| s.drop_pvd())
287 .expect("persisted_validation_data doesn't affect encode_as; qed")
288 }
289
290 pub fn signed_to_compact(signed: SignedFullStatementWithPVD) -> Signed<CompactStatement> {
293 signed
294 .convert_to_superpayload_with(|s| s.to_compact())
295 .expect("doesn't affect encode_as; qed")
296 }
297}
298
299impl From<&'_ StatementWithPVD> for CompactStatement {
300 fn from(stmt: &StatementWithPVD) -> Self {
301 stmt.to_compact()
302 }
303}
304
305impl EncodeAs<CompactStatement> for StatementWithPVD {
306 fn encode_as(&self) -> Vec<u8> {
307 self.to_compact().encode()
308 }
309}
310
311pub type SignedFullStatement = Signed<Statement, CompactStatement>;
318
319pub type UncheckedSignedFullStatement = UncheckedSigned<Statement, CompactStatement>;
321
322pub type SignedFullStatementWithPVD = Signed<StatementWithPVD, CompactStatement>;
328
329#[derive(Debug)]
331pub enum InvalidCandidate {
332 ExecutionError(String),
334 InvalidOutputs,
336 Timeout,
338 ParamsTooLarge(u64),
340 CodeTooLarge(u64),
342 PoVDecompressionFailure,
344 BadReturn,
346 BadParent,
348 PoVHashMismatch,
350 BadSignature,
352 ParaHeadHashMismatch,
354 CodeHashMismatch,
356 CommitmentsHashMismatch,
358 InvalidSessionIndex,
360 InvalidUMPSignals(CommittedCandidateReceiptError),
362}
363
364#[derive(Debug)]
366pub enum ValidationResult {
367 Valid(CandidateCommitments, PersistedValidationData),
370 Invalid(InvalidCandidate),
372}
373
374#[derive(PartialEq, Eq, Clone, Encode, Decode, Debug)]
376pub struct PoV {
377 pub block_data: BlockData,
379}
380
381impl PoV {
382 pub fn hash(&self) -> Hash {
384 BlakeTwo256::hash_of(self)
385 }
386}
387
388#[derive(Clone, Encode, Decode)]
390#[cfg(not(target_os = "unknown"))]
391pub enum MaybeCompressedPoV {
392 Raw(PoV),
394 Compressed(PoV),
396}
397
398#[cfg(not(target_os = "unknown"))]
399impl std::fmt::Debug for MaybeCompressedPoV {
400 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
401 let (variant, size) = match self {
402 MaybeCompressedPoV::Raw(pov) => ("Raw", pov.block_data.0.len()),
403 MaybeCompressedPoV::Compressed(pov) => ("Compressed", pov.block_data.0.len()),
404 };
405
406 write!(f, "{} PoV ({} bytes)", variant, size)
407 }
408}
409
410#[cfg(not(target_os = "unknown"))]
411impl MaybeCompressedPoV {
412 pub fn into_compressed(self) -> PoV {
416 match self {
417 Self::Raw(raw) => maybe_compress_pov(raw),
418 Self::Compressed(compressed) => compressed,
419 }
420 }
421}
422
423#[derive(Debug, Clone, Encode, Decode)]
430#[cfg(not(target_os = "unknown"))]
431pub struct Collation<BlockNumber = polkadot_primitives::BlockNumber> {
432 pub upward_messages: UpwardMessages,
434 pub horizontal_messages: HorizontalMessages,
436 pub new_validation_code: Option<ValidationCode>,
438 pub head_data: HeadData,
440 pub proof_of_validity: MaybeCompressedPoV,
442 pub processed_downward_messages: u32,
444 pub hrmp_watermark: BlockNumber,
447}
448
449#[derive(Debug)]
451#[cfg(not(target_os = "unknown"))]
452pub struct CollationSecondedSignal {
453 pub relay_parent: Hash,
455 pub statement: SignedFullStatement,
459}
460
461#[cfg(not(target_os = "unknown"))]
463pub struct CollationResult {
464 pub collation: Collation,
466 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
472}
473
474#[cfg(not(target_os = "unknown"))]
475impl CollationResult {
476 pub fn into_inner(
478 self,
479 ) -> (Collation, Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>) {
480 (self.collation, self.result_sender)
481 }
482}
483
484#[cfg(not(target_os = "unknown"))]
492pub type CollatorFn = Box<
493 dyn Fn(
494 Hash,
495 &PersistedValidationData,
496 ) -> Pin<Box<dyn Future<Output = Option<CollationResult>> + Send>>
497 + Send
498 + Sync,
499>;
500
501#[cfg(not(target_os = "unknown"))]
503pub struct CollationGenerationConfig {
504 pub key: CollatorPair,
506 pub collator: Option<CollatorFn>,
511 pub para_id: ParaId,
513}
514
515#[cfg(not(target_os = "unknown"))]
516impl std::fmt::Debug for CollationGenerationConfig {
517 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
518 write!(f, "CollationGenerationConfig {{ ... }}")
519 }
520}
521
522#[derive(Debug)]
524pub struct SubmitCollationParams {
525 pub relay_parent: Hash,
527 pub collation: Collation,
529 pub parent_head: HeadData,
531 pub validation_code_hash: ValidationCodeHash,
533 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
539 pub core_index: CoreIndex,
541}
542
543#[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)]
545pub struct AvailableData {
546 pub pov: std::sync::Arc<PoV>,
548 pub validation_data: PersistedValidationData,
550}
551
552#[derive(PartialEq, Eq, Clone, Debug, Hash)]
554pub struct Proof(BoundedVec<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, 1, MERKLE_PROOF_MAX_DEPTH>);
555
556impl Proof {
557 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
559 self.0.iter().map(|v| v.as_slice())
560 }
561
562 pub fn dummy_proof() -> Proof {
566 Proof(BoundedVec::from_vec(vec![BoundedVec::from_vec(vec![0]).unwrap()]).unwrap())
567 }
568}
569
570#[derive(thiserror::Error, Debug)]
572pub enum MerkleProofError {
573 #[error("Merkle max proof depth exceeded {0} > {} .", MERKLE_PROOF_MAX_DEPTH)]
574 MerkleProofDepthExceeded(usize),
576
577 #[error("Merkle node max size exceeded {0} > {} .", MERKLE_NODE_MAX_SIZE)]
578 MerkleProofNodeSizeExceeded(usize),
580}
581
582impl TryFrom<Vec<Vec<u8>>> for Proof {
583 type Error = MerkleProofError;
584
585 fn try_from(input: Vec<Vec<u8>>) -> Result<Self, Self::Error> {
586 if input.len() > MERKLE_PROOF_MAX_DEPTH {
587 return Err(Self::Error::MerkleProofDepthExceeded(input.len()))
588 }
589 let mut out = Vec::new();
590 for element in input.into_iter() {
591 let length = element.len();
592 let data: BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE> = BoundedVec::from_vec(element)
593 .map_err(|_| Self::Error::MerkleProofNodeSizeExceeded(length))?;
594 out.push(data);
595 }
596 Ok(Proof(BoundedVec::from_vec(out).expect("Buffer size is deterined above. qed")))
597 }
598}
599
600impl Decode for Proof {
601 fn decode<I: Input>(value: &mut I) -> Result<Self, CodecError> {
602 let temp: Vec<Vec<u8>> = Decode::decode(value)?;
603 let mut out = Vec::new();
604 for element in temp.into_iter() {
605 let bounded_temp: Result<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, CodecError> =
606 BoundedVec::from_vec(element)
607 .map_err(|_| "Inner node exceeds maximum node size.".into());
608 out.push(bounded_temp?);
609 }
610 BoundedVec::from_vec(out)
611 .map(Self)
612 .map_err(|_| "Merkle proof depth exceeds maximum trie depth".into())
613 }
614}
615
616impl Encode for Proof {
617 fn size_hint(&self) -> usize {
618 MERKLE_NODE_MAX_SIZE * MERKLE_PROOF_MAX_DEPTH
619 }
620
621 fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
622 let temp = self.0.iter().map(|v| v.as_vec()).collect::<Vec<_>>();
623 temp.using_encoded(f)
624 }
625}
626
627impl Serialize for Proof {
628 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
629 where
630 S: Serializer,
631 {
632 serializer.serialize_bytes(&self.encode())
633 }
634}
635
636impl<'de> Deserialize<'de> for Proof {
637 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
638 where
639 D: Deserializer<'de>,
640 {
641 let s = Vec::<u8>::deserialize(deserializer)?;
643 let mut slice = s.as_slice();
644 Decode::decode(&mut slice).map_err(de::Error::custom)
645 }
646}
647
648#[derive(PartialEq, Eq, Clone, Encode, Decode, Serialize, Deserialize, Debug, Hash)]
650pub struct ErasureChunk {
651 pub chunk: Vec<u8>,
653 pub index: ChunkIndex,
655 pub proof: Proof,
657}
658
659impl ErasureChunk {
660 pub fn proof(&self) -> &Proof {
662 &self.proof
663 }
664}
665
666#[cfg(not(target_os = "unknown"))]
668pub fn maybe_compress_pov(pov: PoV) -> PoV {
669 let PoV { block_data: BlockData(raw) } = pov;
670 let raw = sp_maybe_compressed_blob::compress(&raw, POV_BOMB_LIMIT).unwrap_or(raw);
671
672 let pov = PoV { block_data: BlockData(raw) };
673 pov
674}