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 CommittedCandidateReceipt, CompactStatement, CoreIndex, EncodeAs, Hash, HashT, HeadData,
35 Id as ParaId, PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode,
36 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.16.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}
352
353#[derive(Debug)]
355pub enum ValidationResult {
356 Valid(CandidateCommitments, PersistedValidationData),
359 Invalid(InvalidCandidate),
361}
362
363#[derive(PartialEq, Eq, Clone, Encode, Decode, Debug)]
365pub struct PoV {
366 pub block_data: BlockData,
368}
369
370impl PoV {
371 pub fn hash(&self) -> Hash {
373 BlakeTwo256::hash_of(self)
374 }
375}
376
377#[derive(Clone, Encode, Decode)]
379#[cfg(not(target_os = "unknown"))]
380pub enum MaybeCompressedPoV {
381 Raw(PoV),
383 Compressed(PoV),
385}
386
387#[cfg(not(target_os = "unknown"))]
388impl std::fmt::Debug for MaybeCompressedPoV {
389 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
390 let (variant, size) = match self {
391 MaybeCompressedPoV::Raw(pov) => ("Raw", pov.block_data.0.len()),
392 MaybeCompressedPoV::Compressed(pov) => ("Compressed", pov.block_data.0.len()),
393 };
394
395 write!(f, "{} PoV ({} bytes)", variant, size)
396 }
397}
398
399#[cfg(not(target_os = "unknown"))]
400impl MaybeCompressedPoV {
401 pub fn into_compressed(self) -> PoV {
405 match self {
406 Self::Raw(raw) => maybe_compress_pov(raw),
407 Self::Compressed(compressed) => compressed,
408 }
409 }
410}
411
412#[derive(Debug, Clone, Encode, Decode)]
419#[cfg(not(target_os = "unknown"))]
420pub struct Collation<BlockNumber = polkadot_primitives::BlockNumber> {
421 pub upward_messages: UpwardMessages,
423 pub horizontal_messages: HorizontalMessages,
425 pub new_validation_code: Option<ValidationCode>,
427 pub head_data: HeadData,
429 pub proof_of_validity: MaybeCompressedPoV,
431 pub processed_downward_messages: u32,
433 pub hrmp_watermark: BlockNumber,
436}
437
438#[derive(Debug)]
440#[cfg(not(target_os = "unknown"))]
441pub struct CollationSecondedSignal {
442 pub relay_parent: Hash,
444 pub statement: SignedFullStatement,
448}
449
450#[cfg(not(target_os = "unknown"))]
452pub struct CollationResult {
453 pub collation: Collation,
455 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
461}
462
463#[cfg(not(target_os = "unknown"))]
464impl CollationResult {
465 pub fn into_inner(
467 self,
468 ) -> (Collation, Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>) {
469 (self.collation, self.result_sender)
470 }
471}
472
473#[cfg(not(target_os = "unknown"))]
481pub type CollatorFn = Box<
482 dyn Fn(
483 Hash,
484 &PersistedValidationData,
485 ) -> Pin<Box<dyn Future<Output = Option<CollationResult>> + Send>>
486 + Send
487 + Sync,
488>;
489
490#[cfg(not(target_os = "unknown"))]
492pub struct CollationGenerationConfig {
493 pub key: CollatorPair,
495 pub collator: Option<CollatorFn>,
500 pub para_id: ParaId,
502}
503
504#[cfg(not(target_os = "unknown"))]
505impl std::fmt::Debug for CollationGenerationConfig {
506 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
507 write!(f, "CollationGenerationConfig {{ ... }}")
508 }
509}
510
511#[derive(Debug)]
513pub struct SubmitCollationParams {
514 pub relay_parent: Hash,
516 pub collation: Collation,
518 pub parent_head: HeadData,
520 pub validation_code_hash: ValidationCodeHash,
522 pub result_sender: Option<futures::channel::oneshot::Sender<CollationSecondedSignal>>,
528 pub core_index: CoreIndex,
530}
531
532#[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)]
534pub struct AvailableData {
535 pub pov: std::sync::Arc<PoV>,
537 pub validation_data: PersistedValidationData,
539}
540
541#[derive(PartialEq, Eq, Clone, Debug, Hash)]
543pub struct Proof(BoundedVec<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, 1, MERKLE_PROOF_MAX_DEPTH>);
544
545impl Proof {
546 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
548 self.0.iter().map(|v| v.as_slice())
549 }
550
551 pub fn dummy_proof() -> Proof {
555 Proof(BoundedVec::from_vec(vec![BoundedVec::from_vec(vec![0]).unwrap()]).unwrap())
556 }
557}
558
559#[derive(thiserror::Error, Debug)]
561pub enum MerkleProofError {
562 #[error("Merkle max proof depth exceeded {0} > {} .", MERKLE_PROOF_MAX_DEPTH)]
563 MerkleProofDepthExceeded(usize),
565
566 #[error("Merkle node max size exceeded {0} > {} .", MERKLE_NODE_MAX_SIZE)]
567 MerkleProofNodeSizeExceeded(usize),
569}
570
571impl TryFrom<Vec<Vec<u8>>> for Proof {
572 type Error = MerkleProofError;
573
574 fn try_from(input: Vec<Vec<u8>>) -> Result<Self, Self::Error> {
575 if input.len() > MERKLE_PROOF_MAX_DEPTH {
576 return Err(Self::Error::MerkleProofDepthExceeded(input.len()))
577 }
578 let mut out = Vec::new();
579 for element in input.into_iter() {
580 let length = element.len();
581 let data: BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE> = BoundedVec::from_vec(element)
582 .map_err(|_| Self::Error::MerkleProofNodeSizeExceeded(length))?;
583 out.push(data);
584 }
585 Ok(Proof(BoundedVec::from_vec(out).expect("Buffer size is deterined above. qed")))
586 }
587}
588
589impl Decode for Proof {
590 fn decode<I: Input>(value: &mut I) -> Result<Self, CodecError> {
591 let temp: Vec<Vec<u8>> = Decode::decode(value)?;
592 let mut out = Vec::new();
593 for element in temp.into_iter() {
594 let bounded_temp: Result<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, CodecError> =
595 BoundedVec::from_vec(element)
596 .map_err(|_| "Inner node exceeds maximum node size.".into());
597 out.push(bounded_temp?);
598 }
599 BoundedVec::from_vec(out)
600 .map(Self)
601 .map_err(|_| "Merkle proof depth exceeds maximum trie depth".into())
602 }
603}
604
605impl Encode for Proof {
606 fn size_hint(&self) -> usize {
607 MERKLE_NODE_MAX_SIZE * MERKLE_PROOF_MAX_DEPTH
608 }
609
610 fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
611 let temp = self.0.iter().map(|v| v.as_vec()).collect::<Vec<_>>();
612 temp.using_encoded(f)
613 }
614}
615
616impl Serialize for Proof {
617 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
618 where
619 S: Serializer,
620 {
621 serializer.serialize_bytes(&self.encode())
622 }
623}
624
625impl<'de> Deserialize<'de> for Proof {
626 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
627 where
628 D: Deserializer<'de>,
629 {
630 let s = Vec::<u8>::deserialize(deserializer)?;
632 let mut slice = s.as_slice();
633 Decode::decode(&mut slice).map_err(de::Error::custom)
634 }
635}
636
637#[derive(PartialEq, Eq, Clone, Encode, Decode, Serialize, Deserialize, Debug, Hash)]
639pub struct ErasureChunk {
640 pub chunk: Vec<u8>,
642 pub index: ChunkIndex,
644 pub proof: Proof,
646}
647
648impl ErasureChunk {
649 pub fn proof(&self) -> &Proof {
651 &self.proof
652 }
653}
654
655#[cfg(not(target_os = "unknown"))]
657pub fn maybe_compress_pov(pov: PoV) -> PoV {
658 let PoV { block_data: BlockData(raw) } = pov;
659 let raw = sp_maybe_compressed_blob::compress(&raw, POV_BOMB_LIMIT).unwrap_or(raw);
660
661 let pov = PoV { block_data: BlockData(raw) };
662 pov
663}