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::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, BlakeTwo256, BlockNumber,
34 CandidateCommitments, CandidateHash, ChunkIndex, CollatorPair, CompactStatement, CoreIndex,
35 EncodeAs, Hash, HashT, HeadData, Id as ParaId, PersistedValidationData, SessionIndex, Signed,
36 UncheckedSigned, ValidationCode, ValidationCodeHash, MAX_CODE_SIZE, MAX_POV_SIZE,
37};
38pub use sp_consensus_babe::{
39 AllowedSlots as BabeAllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch,
40 Randomness as BabeRandomness,
41};
42
43pub use polkadot_parachain_primitives::primitives::{
44 BlockData, HorizontalMessages, UpwardMessages,
45};
46
47pub mod approval;
48
49pub mod disputes;
51pub use disputes::{
52 dispute_is_inactive, CandidateVotes, DisputeMessage, DisputeMessageCheckError, DisputeStatus,
53 InvalidDisputeVote, SignedDisputeStatement, Timestamp, UncheckedDisputeMessage,
54 ValidDisputeVote, ACTIVE_DURATION_SECS,
55};
56
57pub const NODE_VERSION: &'static str = "1.17.0";
63
64const MERKLE_NODE_MAX_SIZE: usize = 512 + 100;
68const MERKLE_PROOF_MAX_DEPTH: usize = 8;
70
71pub const VALIDATION_CODE_BOMB_LIMIT: usize = (MAX_CODE_SIZE * 4u32) as usize;
73
74pub const POV_BOMB_LIMIT: usize = (MAX_POV_SIZE * 4u32) as usize;
76
77pub const DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION: BlockNumber = 10;
99
100pub const MAX_FINALITY_LAG: u32 = 500;
104
105#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
112pub struct SessionWindowSize(SessionIndex);
113
114#[macro_export]
115macro_rules! new_session_window_size {
117 (0) => {
118 compile_error!("Must be non zero");
119 };
120 (0_u32) => {
121 compile_error!("Must be non zero");
122 };
123 (0 as u32) => {
124 compile_error!("Must be non zero");
125 };
126 (0 as _) => {
127 compile_error!("Must be non zero");
128 };
129 ($l:literal) => {
130 SessionWindowSize::unchecked_new($l as _)
131 };
132}
133
134pub const DISPUTE_WINDOW: SessionWindowSize = new_session_window_size!(6);
139
140impl SessionWindowSize {
141 pub fn get(self) -> SessionIndex {
143 self.0
144 }
145
146 #[doc(hidden)]
151 pub const fn unchecked_new(size: SessionIndex) -> Self {
152 Self(size)
153 }
154}
155
156pub type BlockWeight = u32;
158
159#[derive(Clone, PartialEq, Eq, Encode, Decode)]
166pub enum Statement {
167 #[codec(index = 1)]
169 Seconded(CommittedCandidateReceipt),
170 #[codec(index = 2)]
172 Valid(CandidateHash),
173}
174
175impl std::fmt::Debug for Statement {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 match self {
178 Statement::Seconded(seconded) => write!(f, "Seconded: {:?}", seconded.descriptor),
179 Statement::Valid(hash) => write!(f, "Valid: {:?}", hash),
180 }
181 }
182}
183
184impl Statement {
185 pub fn candidate_hash(&self) -> CandidateHash {
190 match *self {
191 Statement::Valid(ref h) => *h,
192 Statement::Seconded(ref c) => c.hash(),
193 }
194 }
195
196 pub fn to_compact(&self) -> CompactStatement {
199 match *self {
200 Statement::Seconded(ref c) => CompactStatement::Seconded(c.hash()),
201 Statement::Valid(hash) => CompactStatement::Valid(hash),
202 }
203 }
204
205 pub fn supply_pvd(self, pvd: PersistedValidationData) -> StatementWithPVD {
207 match self {
208 Statement::Seconded(c) => StatementWithPVD::Seconded(c, pvd),
209 Statement::Valid(hash) => StatementWithPVD::Valid(hash),
210 }
211 }
212}
213
214impl From<&'_ Statement> for CompactStatement {
215 fn from(stmt: &Statement) -> Self {
216 stmt.to_compact()
217 }
218}
219
220impl EncodeAs<CompactStatement> for Statement {
221 fn encode_as(&self) -> Vec<u8> {
222 self.to_compact().encode()
223 }
224}
225
226#[derive(Clone, PartialEq, Eq)]
229pub enum StatementWithPVD {
230 Seconded(CommittedCandidateReceipt, PersistedValidationData),
232 Valid(CandidateHash),
234}
235
236impl std::fmt::Debug for StatementWithPVD {
237 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238 match self {
239 StatementWithPVD::Seconded(seconded, _) =>
240 write!(f, "Seconded: {:?}", seconded.descriptor),
241 StatementWithPVD::Valid(hash) => write!(f, "Valid: {:?}", hash),
242 }
243 }
244}
245
246impl StatementWithPVD {
247 pub fn candidate_hash(&self) -> CandidateHash {
252 match *self {
253 StatementWithPVD::Valid(ref h) => *h,
254 StatementWithPVD::Seconded(ref c, _) => c.hash(),
255 }
256 }
257
258 pub fn to_compact(&self) -> CompactStatement {
261 match *self {
262 StatementWithPVD::Seconded(ref c, _) => CompactStatement::Seconded(c.hash()),
263 StatementWithPVD::Valid(hash) => CompactStatement::Valid(hash),
264 }
265 }
266
267 pub fn drop_pvd(self) -> Statement {
269 match self {
270 StatementWithPVD::Seconded(c, _) => Statement::Seconded(c),
271 StatementWithPVD::Valid(c_h) => Statement::Valid(c_h),
272 }
273 }
274
275 pub fn drop_pvd_from_signed(signed: SignedFullStatementWithPVD) -> SignedFullStatement {
278 signed
279 .convert_to_superpayload_with(|s| s.drop_pvd())
280 .expect("persisted_validation_data doesn't affect encode_as; qed")
281 }
282
283 pub fn signed_to_compact(signed: SignedFullStatementWithPVD) -> Signed<CompactStatement> {
286 signed
287 .convert_to_superpayload_with(|s| s.to_compact())
288 .expect("doesn't affect encode_as; qed")
289 }
290}
291
292impl From<&'_ StatementWithPVD> for CompactStatement {
293 fn from(stmt: &StatementWithPVD) -> Self {
294 stmt.to_compact()
295 }
296}
297
298impl EncodeAs<CompactStatement> for StatementWithPVD {
299 fn encode_as(&self) -> Vec<u8> {
300 self.to_compact().encode()
301 }
302}
303
304pub type SignedFullStatement = Signed<Statement, CompactStatement>;
311
312pub type UncheckedSignedFullStatement = UncheckedSigned<Statement, CompactStatement>;
314
315pub type SignedFullStatementWithPVD = Signed<StatementWithPVD, CompactStatement>;
321
322#[derive(Debug)]
324pub enum InvalidCandidate {
325 ExecutionError(String),
327 InvalidOutputs,
329 Timeout,
331 ParamsTooLarge(u64),
333 CodeTooLarge(u64),
335 PoVDecompressionFailure,
337 BadReturn,
339 BadParent,
341 PoVHashMismatch,
343 BadSignature,
345 ParaHeadHashMismatch,
347 CodeHashMismatch,
349 CommitmentsHashMismatch,
351 InvalidSessionIndex,
353 InvalidCoreIndex,
355}
356
357#[derive(Debug)]
359pub enum ValidationResult {
360 Valid(CandidateCommitments, PersistedValidationData),
363 Invalid(InvalidCandidate),
365}
366
367#[derive(PartialEq, Eq, Clone, Encode, Decode, Debug)]
369pub struct PoV {
370 pub block_data: BlockData,
372}
373
374impl PoV {
375 pub fn hash(&self) -> Hash {
377 BlakeTwo256::hash_of(self)
378 }
379}
380
381#[derive(Clone, Encode, Decode)]
383#[cfg(not(target_os = "unknown"))]
384pub enum MaybeCompressedPoV {
385 Raw(PoV),
387 Compressed(PoV),
389}
390
391#[cfg(not(target_os = "unknown"))]
392impl std::fmt::Debug for MaybeCompressedPoV {
393 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
394 let (variant, size) = match self {
395 MaybeCompressedPoV::Raw(pov) => ("Raw", pov.block_data.0.len()),
396 MaybeCompressedPoV::Compressed(pov) => ("Compressed", pov.block_data.0.len()),
397 };
398
399 write!(f, "{} PoV ({} bytes)", variant, size)
400 }
401}
402
403#[cfg(not(target_os = "unknown"))]
404impl MaybeCompressedPoV {
405 pub fn into_compressed(self) -> PoV {
409 match self {
410 Self::Raw(raw) => maybe_compress_pov(raw),
411 Self::Compressed(compressed) => compressed,
412 }
413 }
414}
415
416#[derive(Debug, Clone, Encode, Decode)]
423#[cfg(not(target_os = "unknown"))]
424pub struct Collation<BlockNumber = polkadot_primitives::BlockNumber> {
425 pub upward_messages: UpwardMessages,
427 pub horizontal_messages: HorizontalMessages,
429 pub new_validation_code: Option<ValidationCode>,
431 pub head_data: HeadData,
433 pub proof_of_validity: MaybeCompressedPoV,
435 pub processed_downward_messages: u32,
437 pub hrmp_watermark: BlockNumber,
440}
441
442#[derive(Debug)]
444#[cfg(not(target_os = "unknown"))]
445pub struct CollationSecondedSignal {
446 pub relay_parent: Hash,
448 pub statement: SignedFullStatement,
452}
453
454#[cfg(not(target_os = "unknown"))]
456pub struct CollationResult {
457 pub collation: Collation,
459 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
465}
466
467#[cfg(not(target_os = "unknown"))]
468impl CollationResult {
469 pub fn into_inner(
471 self,
472 ) -> (Collation, Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>) {
473 (self.collation, self.result_sender)
474 }
475}
476
477#[cfg(not(target_os = "unknown"))]
485pub type CollatorFn = Box<
486 dyn Fn(
487 Hash,
488 &PersistedValidationData,
489 ) -> Pin<Box<dyn Future<Output = Option<CollationResult>> + Send>>
490 + Send
491 + Sync,
492>;
493
494#[cfg(not(target_os = "unknown"))]
496pub struct CollationGenerationConfig {
497 pub key: CollatorPair,
499 pub collator: Option<CollatorFn>,
504 pub para_id: ParaId,
506}
507
508#[cfg(not(target_os = "unknown"))]
509impl std::fmt::Debug for CollationGenerationConfig {
510 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
511 write!(f, "CollationGenerationConfig {{ ... }}")
512 }
513}
514
515#[derive(Debug)]
517pub struct SubmitCollationParams {
518 pub relay_parent: Hash,
520 pub collation: Collation,
522 pub parent_head: HeadData,
524 pub validation_code_hash: ValidationCodeHash,
526 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
532 pub core_index: CoreIndex,
534}
535
536#[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)]
538pub struct AvailableData {
539 pub pov: std::sync::Arc<PoV>,
541 pub validation_data: PersistedValidationData,
543}
544
545#[derive(PartialEq, Eq, Clone, Debug, Hash)]
547pub struct Proof(BoundedVec<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, 1, MERKLE_PROOF_MAX_DEPTH>);
548
549impl Proof {
550 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
552 self.0.iter().map(|v| v.as_slice())
553 }
554
555 pub fn dummy_proof() -> Proof {
559 Proof(BoundedVec::from_vec(vec![BoundedVec::from_vec(vec![0]).unwrap()]).unwrap())
560 }
561}
562
563#[derive(thiserror::Error, Debug)]
565pub enum MerkleProofError {
566 #[error("Merkle max proof depth exceeded {0} > {} .", MERKLE_PROOF_MAX_DEPTH)]
567 MerkleProofDepthExceeded(usize),
569
570 #[error("Merkle node max size exceeded {0} > {} .", MERKLE_NODE_MAX_SIZE)]
571 MerkleProofNodeSizeExceeded(usize),
573}
574
575impl TryFrom<Vec<Vec<u8>>> for Proof {
576 type Error = MerkleProofError;
577
578 fn try_from(input: Vec<Vec<u8>>) -> Result<Self, Self::Error> {
579 if input.len() > MERKLE_PROOF_MAX_DEPTH {
580 return Err(Self::Error::MerkleProofDepthExceeded(input.len()))
581 }
582 let mut out = Vec::new();
583 for element in input.into_iter() {
584 let length = element.len();
585 let data: BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE> = BoundedVec::from_vec(element)
586 .map_err(|_| Self::Error::MerkleProofNodeSizeExceeded(length))?;
587 out.push(data);
588 }
589 Ok(Proof(BoundedVec::from_vec(out).expect("Buffer size is deterined above. qed")))
590 }
591}
592
593impl Decode for Proof {
594 fn decode<I: Input>(value: &mut I) -> Result<Self, CodecError> {
595 let temp: Vec<Vec<u8>> = Decode::decode(value)?;
596 let mut out = Vec::new();
597 for element in temp.into_iter() {
598 let bounded_temp: Result<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, CodecError> =
599 BoundedVec::from_vec(element)
600 .map_err(|_| "Inner node exceeds maximum node size.".into());
601 out.push(bounded_temp?);
602 }
603 BoundedVec::from_vec(out)
604 .map(Self)
605 .map_err(|_| "Merkle proof depth exceeds maximum trie depth".into())
606 }
607}
608
609impl Encode for Proof {
610 fn size_hint(&self) -> usize {
611 MERKLE_NODE_MAX_SIZE * MERKLE_PROOF_MAX_DEPTH
612 }
613
614 fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
615 let temp = self.0.iter().map(|v| v.as_vec()).collect::<Vec<_>>();
616 temp.using_encoded(f)
617 }
618}
619
620impl Serialize for Proof {
621 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
622 where
623 S: Serializer,
624 {
625 serializer.serialize_bytes(&self.encode())
626 }
627}
628
629impl<'de> Deserialize<'de> for Proof {
630 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
631 where
632 D: Deserializer<'de>,
633 {
634 let s = Vec::<u8>::deserialize(deserializer)?;
636 let mut slice = s.as_slice();
637 Decode::decode(&mut slice).map_err(de::Error::custom)
638 }
639}
640
641#[derive(PartialEq, Eq, Clone, Encode, Decode, Serialize, Deserialize, Debug, Hash)]
643pub struct ErasureChunk {
644 pub chunk: Vec<u8>,
646 pub index: ChunkIndex,
648 pub proof: Proof,
650}
651
652impl ErasureChunk {
653 pub fn proof(&self) -> &Proof {
655 &self.proof
656 }
657}
658
659#[cfg(not(target_os = "unknown"))]
661pub fn maybe_compress_pov(pov: PoV) -> PoV {
662 let PoV { block_data: BlockData(raw) } = pov;
663 let raw = sp_maybe_compressed_blob::compress(&raw, POV_BOMB_LIMIT).unwrap_or(raw);
664
665 let pov = PoV { block_data: BlockData(raw) };
666 pov
667}