1#![cfg_attr(not(feature = "std"), no_std)]
20
21extern crate alloc;
22
23use alloc::vec::Vec;
24use codec::{Compact, Decode, DecodeAll, DecodeWithMemTracking, Encode, MaxEncodedLen};
25use polkadot_parachain_primitives::primitives::HeadData;
26use scale_info::TypeInfo;
27use sp_runtime::RuntimeDebug;
28
29pub const REF_TIME_PER_CORE_IN_SECS: u64 = 2;
33
34pub mod parachain_block_data;
35
36pub use parachain_block_data::ParachainBlockData;
37pub use polkadot_core_primitives::InboundDownwardMessage;
38pub use polkadot_parachain_primitives::primitives::{
39 DmpMessageHandler, Id as ParaId, IsSystem, UpwardMessage, ValidationParams, XcmpMessageFormat,
40 XcmpMessageHandler,
41};
42pub use polkadot_primitives::{
43 AbridgedHostConfiguration, AbridgedHrmpChannel, ClaimQueueOffset, CoreSelector,
44 PersistedValidationData,
45};
46pub use sp_runtime::{
47 generic::{Digest, DigestItem},
48 traits::Block as BlockT,
49 ConsensusEngineId,
50};
51pub use xcm::latest::prelude::*;
52
53pub mod relay_chain {
55 pub use polkadot_core_primitives::*;
56 pub use polkadot_primitives::*;
57}
58
59pub type InboundHrmpMessage = polkadot_primitives::InboundHrmpMessage<relay_chain::BlockNumber>;
61
62pub type OutboundHrmpMessage = polkadot_primitives::OutboundHrmpMessage<ParaId>;
64
65#[derive(Eq, PartialEq, Copy, Clone, RuntimeDebug, Encode, Decode)]
67pub enum MessageSendError {
68 QueueFull,
70 NoChannel,
72 TooBig,
74 Other,
76 TooManyChannels,
78}
79
80impl From<MessageSendError> for &'static str {
81 fn from(e: MessageSendError) -> Self {
82 use MessageSendError::*;
83 match e {
84 QueueFull => "QueueFull",
85 NoChannel => "NoChannel",
86 TooBig => "TooBig",
87 Other => "Other",
88 TooManyChannels => "TooManyChannels",
89 }
90 }
91}
92
93#[derive(
95 Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, Clone, Eq, PartialEq, TypeInfo, Debug,
96)]
97pub enum AggregateMessageOrigin {
98 Here,
100 Parent,
104 Sibling(ParaId),
108}
109
110impl From<AggregateMessageOrigin> for Location {
111 fn from(origin: AggregateMessageOrigin) -> Self {
112 match origin {
113 AggregateMessageOrigin::Here => Location::here(),
114 AggregateMessageOrigin::Parent => Location::parent(),
115 AggregateMessageOrigin::Sibling(id) => Location::new(1, Junction::Parachain(id.into())),
116 }
117 }
118}
119
120#[cfg(feature = "runtime-benchmarks")]
121impl From<u32> for AggregateMessageOrigin {
122 fn from(x: u32) -> Self {
123 match x {
124 0 => Self::Here,
125 1 => Self::Parent,
126 p => Self::Sibling(ParaId::from(p)),
127 }
128 }
129}
130
131pub struct ChannelInfo {
133 pub max_capacity: u32,
135 pub max_total_size: u32,
137 pub max_message_size: u32,
139 pub msg_count: u32,
142 pub total_size: u32,
145}
146
147pub trait GetChannelInfo {
148 fn get_channel_status(id: ParaId) -> ChannelStatus;
149 fn get_channel_info(id: ParaId) -> Option<ChannelInfo>;
150}
151
152pub trait ListChannelInfos {
154 fn outgoing_channels() -> Vec<ParaId>;
155}
156
157pub trait UpwardMessageSender {
159 fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError>;
163
164 fn can_send_upward_message(message: &UpwardMessage) -> Result<(), MessageSendError>;
166
167 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
169 fn ensure_successful_delivery() {}
170}
171
172impl UpwardMessageSender for () {
173 fn send_upward_message(_message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
174 Err(MessageSendError::NoChannel)
175 }
176
177 fn can_send_upward_message(_message: &UpwardMessage) -> Result<(), MessageSendError> {
178 Err(MessageSendError::Other)
179 }
180}
181
182pub enum ChannelStatus {
184 Closed,
186 Full,
188 Ready(usize, usize),
193}
194
195pub trait XcmpMessageSource {
197 fn take_outbound_messages(maximum_channels: usize) -> Vec<(ParaId, Vec<u8>)>;
199}
200
201impl XcmpMessageSource for () {
202 fn take_outbound_messages(_maximum_channels: usize) -> Vec<(ParaId, Vec<u8>)> {
203 Vec::new()
204 }
205}
206
207#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, RuntimeDebug)]
209pub enum ServiceQuality {
210 Ordered,
214 Fast,
217}
218
219pub const CUMULUS_CONSENSUS_ID: ConsensusEngineId = *b"CMLS";
221
222#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)]
224pub struct CoreInfo {
225 pub selector: CoreSelector,
227 pub claim_queue_offset: ClaimQueueOffset,
229 pub number_of_cores: Compact<u16>,
231}
232
233#[derive(Debug, Clone, PartialEq, Eq)]
235pub enum CoreInfoExistsAtMaxOnce {
236 Once(CoreInfo),
238 NotFound,
240 MoreThanOnce,
242}
243
244#[derive(Clone, Debug, PartialEq, Hash, Eq)]
246pub enum RelayBlockIdentifier {
247 ByHash(relay_chain::Hash),
249 ByStorageRoot { storage_root: relay_chain::Hash, block_number: relay_chain::BlockNumber },
251}
252
253#[derive(Clone, Debug, Decode, Encode, PartialEq)]
255pub enum CumulusDigestItem {
256 #[codec(index = 0)]
258 RelayParent(relay_chain::Hash),
259 #[codec(index = 1)]
262 CoreInfo(CoreInfo),
263}
264
265impl CumulusDigestItem {
266 pub fn to_digest_item(&self) -> DigestItem {
268 match self {
269 Self::RelayParent(_) => DigestItem::Consensus(CUMULUS_CONSENSUS_ID, self.encode()),
270 Self::CoreInfo(_) => DigestItem::PreRuntime(CUMULUS_CONSENSUS_ID, self.encode()),
271 }
272 }
273
274 pub fn find_core_info(digest: &Digest) -> Option<CoreInfo> {
278 digest.convert_first(|d| match d {
279 DigestItem::PreRuntime(id, val) if id == &CUMULUS_CONSENSUS_ID => {
280 let Ok(CumulusDigestItem::CoreInfo(core_info)) =
281 CumulusDigestItem::decode_all(&mut &val[..])
282 else {
283 return None
284 };
285
286 Some(core_info)
287 },
288 _ => None,
289 })
290 }
291
292 pub fn core_info_exists_at_max_once(digest: &Digest) -> CoreInfoExistsAtMaxOnce {
295 let mut core_info = None;
296 if digest
297 .logs()
298 .iter()
299 .filter(|l| match l {
300 DigestItem::PreRuntime(CUMULUS_CONSENSUS_ID, d) => {
301 if let Ok(Self::CoreInfo(ci)) = Self::decode_all(&mut &d[..]) {
302 core_info = Some(ci);
303 true
304 } else {
305 false
306 }
307 },
308 _ => false,
309 })
310 .count() <= 1
311 {
312 core_info
313 .map(CoreInfoExistsAtMaxOnce::Once)
314 .unwrap_or(CoreInfoExistsAtMaxOnce::NotFound)
315 } else {
316 CoreInfoExistsAtMaxOnce::MoreThanOnce
317 }
318 }
319
320 pub fn find_relay_block_identifier(digest: &Digest) -> Option<RelayBlockIdentifier> {
324 digest.convert_first(|d| match d {
325 DigestItem::Consensus(id, val) if id == &CUMULUS_CONSENSUS_ID => {
326 let Ok(CumulusDigestItem::RelayParent(hash)) =
327 CumulusDigestItem::decode_all(&mut &val[..])
328 else {
329 return None
330 };
331
332 Some(RelayBlockIdentifier::ByHash(hash))
333 },
334 DigestItem::Consensus(id, val) if id == &rpsr_digest::RPSR_CONSENSUS_ID => {
335 let Ok((storage_root, block_number)) =
336 rpsr_digest::RpsrType::decode_all(&mut &val[..])
337 else {
338 return None
339 };
340
341 Some(RelayBlockIdentifier::ByStorageRoot {
342 storage_root,
343 block_number: block_number.into(),
344 })
345 },
346 _ => None,
347 })
348 }
349}
350
351pub fn extract_relay_parent(digest: &Digest) -> Option<relay_chain::Hash> {
355 digest.convert_first(|d| match d {
356 DigestItem::Consensus(id, val) if id == &CUMULUS_CONSENSUS_ID =>
357 match CumulusDigestItem::decode(&mut &val[..]) {
358 Ok(CumulusDigestItem::RelayParent(hash)) => Some(hash),
359 _ => None,
360 },
361 _ => None,
362 })
363}
364
365#[doc(hidden)]
382pub mod rpsr_digest {
383 use super::{relay_chain, ConsensusEngineId, DecodeAll, Digest, DigestItem, Encode};
384 use codec::Compact;
385
386 pub type RpsrType = (relay_chain::Hash, Compact<relay_chain::BlockNumber>);
388
389 pub const RPSR_CONSENSUS_ID: ConsensusEngineId = *b"RPSR";
391
392 pub fn relay_parent_storage_root_item(
394 storage_root: relay_chain::Hash,
395 number: impl Into<Compact<relay_chain::BlockNumber>>,
396 ) -> DigestItem {
397 DigestItem::Consensus(
398 RPSR_CONSENSUS_ID,
399 RpsrType::from((storage_root, number.into())).encode(),
400 )
401 }
402
403 pub fn extract_relay_parent_storage_root(
406 digest: &Digest,
407 ) -> Option<(relay_chain::Hash, relay_chain::BlockNumber)> {
408 digest.convert_first(|d| match d {
409 DigestItem::Consensus(id, val) if id == &RPSR_CONSENSUS_ID => {
410 let (h, n) = RpsrType::decode_all(&mut &val[..]).ok()?;
411
412 Some((h, n.0))
413 },
414 _ => None,
415 })
416 }
417}
418
419#[derive(Clone, Debug, codec::Decode, codec::Encode, PartialEq)]
423pub struct CollationInfoV1 {
424 pub upward_messages: Vec<UpwardMessage>,
426 pub horizontal_messages: Vec<OutboundHrmpMessage>,
428 pub new_validation_code: Option<relay_chain::ValidationCode>,
430 pub processed_downward_messages: u32,
432 pub hrmp_watermark: relay_chain::BlockNumber,
435}
436
437impl CollationInfoV1 {
438 pub fn into_latest(self, head_data: HeadData) -> CollationInfo {
440 CollationInfo {
441 upward_messages: self.upward_messages,
442 horizontal_messages: self.horizontal_messages,
443 new_validation_code: self.new_validation_code,
444 processed_downward_messages: self.processed_downward_messages,
445 hrmp_watermark: self.hrmp_watermark,
446 head_data,
447 }
448 }
449}
450
451#[derive(Clone, Debug, codec::Decode, codec::Encode, PartialEq, TypeInfo)]
453pub struct CollationInfo {
454 pub upward_messages: Vec<UpwardMessage>,
456 pub horizontal_messages: Vec<OutboundHrmpMessage>,
458 pub new_validation_code: Option<relay_chain::ValidationCode>,
460 pub processed_downward_messages: u32,
462 pub hrmp_watermark: relay_chain::BlockNumber,
465 pub head_data: HeadData,
467}
468
469sp_api::decl_runtime_apis! {
470 #[api_version(3)]
476 pub trait CollectCollationInfo {
477 #[changed_in(2)]
479 fn collect_collation_info() -> CollationInfoV1;
480 fn collect_collation_info(header: &Block::Header) -> CollationInfo;
485 }
486
487 pub trait GetParachainInfo {
489 fn parachain_id() -> ParaId;
491 }
492
493 pub trait RelayParentOffsetApi {
498 fn relay_parent_offset() -> u32;
500 }
501
502 pub trait TargetBlockRate {
511 fn target_block_rate() -> u32;
515 }
516}