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 mod parachain_block_data;
30
31pub use parachain_block_data::ParachainBlockData;
32pub use polkadot_core_primitives::InboundDownwardMessage;
33pub use polkadot_parachain_primitives::primitives::{
34 DmpMessageHandler, Id as ParaId, IsSystem, UpwardMessage, ValidationParams, XcmpMessageFormat,
35 XcmpMessageHandler,
36};
37pub use polkadot_primitives::{
38 AbridgedHostConfiguration, AbridgedHrmpChannel, ClaimQueueOffset, CoreSelector,
39 PersistedValidationData,
40};
41pub use sp_runtime::{
42 generic::{Digest, DigestItem},
43 traits::Block as BlockT,
44 ConsensusEngineId,
45};
46pub use xcm::latest::prelude::*;
47
48pub mod relay_chain {
50 pub use polkadot_core_primitives::*;
51 pub use polkadot_primitives::*;
52}
53
54pub type InboundHrmpMessage = polkadot_primitives::InboundHrmpMessage<relay_chain::BlockNumber>;
56
57pub type OutboundHrmpMessage = polkadot_primitives::OutboundHrmpMessage<ParaId>;
59
60#[derive(Eq, PartialEq, Copy, Clone, RuntimeDebug, Encode, Decode)]
62pub enum MessageSendError {
63 QueueFull,
65 NoChannel,
67 TooBig,
69 Other,
71 TooManyChannels,
73}
74
75impl From<MessageSendError> for &'static str {
76 fn from(e: MessageSendError) -> Self {
77 use MessageSendError::*;
78 match e {
79 QueueFull => "QueueFull",
80 NoChannel => "NoChannel",
81 TooBig => "TooBig",
82 Other => "Other",
83 TooManyChannels => "TooManyChannels",
84 }
85 }
86}
87
88#[derive(
90 Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, Clone, Eq, PartialEq, TypeInfo, Debug,
91)]
92pub enum AggregateMessageOrigin {
93 Here,
95 Parent,
99 Sibling(ParaId),
103}
104
105impl From<AggregateMessageOrigin> for Location {
106 fn from(origin: AggregateMessageOrigin) -> Self {
107 match origin {
108 AggregateMessageOrigin::Here => Location::here(),
109 AggregateMessageOrigin::Parent => Location::parent(),
110 AggregateMessageOrigin::Sibling(id) => Location::new(1, Junction::Parachain(id.into())),
111 }
112 }
113}
114
115#[cfg(feature = "runtime-benchmarks")]
116impl From<u32> for AggregateMessageOrigin {
117 fn from(x: u32) -> Self {
118 match x {
119 0 => Self::Here,
120 1 => Self::Parent,
121 p => Self::Sibling(ParaId::from(p)),
122 }
123 }
124}
125
126pub struct ChannelInfo {
128 pub max_capacity: u32,
130 pub max_total_size: u32,
132 pub max_message_size: u32,
134 pub msg_count: u32,
137 pub total_size: u32,
140}
141
142pub trait GetChannelInfo {
143 fn get_channel_status(id: ParaId) -> ChannelStatus;
144 fn get_channel_info(id: ParaId) -> Option<ChannelInfo>;
145}
146
147pub trait ListChannelInfos {
149 fn outgoing_channels() -> Vec<ParaId>;
150}
151
152pub trait UpwardMessageSender {
154 fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError>;
158
159 fn can_send_upward_message(message: &UpwardMessage) -> Result<(), MessageSendError>;
161
162 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
164 fn ensure_successful_delivery() {}
165}
166
167impl UpwardMessageSender for () {
168 fn send_upward_message(_message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
169 Err(MessageSendError::NoChannel)
170 }
171
172 fn can_send_upward_message(_message: &UpwardMessage) -> Result<(), MessageSendError> {
173 Err(MessageSendError::Other)
174 }
175}
176
177pub enum ChannelStatus {
179 Closed,
181 Full,
183 Ready(usize, usize),
188}
189
190pub trait XcmpMessageSource {
192 fn take_outbound_messages(maximum_channels: usize) -> Vec<(ParaId, Vec<u8>)>;
194}
195
196impl XcmpMessageSource for () {
197 fn take_outbound_messages(_maximum_channels: usize) -> Vec<(ParaId, Vec<u8>)> {
198 Vec::new()
199 }
200}
201
202#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, RuntimeDebug)]
204pub enum ServiceQuality {
205 Ordered,
209 Fast,
212}
213
214pub const CUMULUS_CONSENSUS_ID: ConsensusEngineId = *b"CMLS";
216
217#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)]
219pub struct CoreInfo {
220 pub selector: CoreSelector,
222 pub claim_queue_offset: ClaimQueueOffset,
224 pub number_of_cores: Compact<u16>,
226}
227
228#[derive(Debug, Clone, PartialEq, Eq)]
230pub enum CoreInfoExistsAtMaxOnce {
231 Once(CoreInfo),
233 NotFound,
235 MoreThanOnce,
237}
238
239#[derive(Clone, Debug, PartialEq, Hash, Eq)]
241pub enum RelayBlockIdentifier {
242 ByHash(relay_chain::Hash),
244 ByStorageRoot { storage_root: relay_chain::Hash, block_number: relay_chain::BlockNumber },
246}
247
248#[derive(Clone, Debug, Decode, Encode, PartialEq)]
250pub enum CumulusDigestItem {
251 #[codec(index = 0)]
253 RelayParent(relay_chain::Hash),
254 #[codec(index = 1)]
257 CoreInfo(CoreInfo),
258}
259
260impl CumulusDigestItem {
261 pub fn to_digest_item(&self) -> DigestItem {
263 match self {
264 Self::RelayParent(_) => DigestItem::Consensus(CUMULUS_CONSENSUS_ID, self.encode()),
265 Self::CoreInfo(_) => DigestItem::PreRuntime(CUMULUS_CONSENSUS_ID, self.encode()),
266 }
267 }
268
269 pub fn find_core_info(digest: &Digest) -> Option<CoreInfo> {
273 digest.convert_first(|d| match d {
274 DigestItem::PreRuntime(id, val) if id == &CUMULUS_CONSENSUS_ID => {
275 let Ok(CumulusDigestItem::CoreInfo(core_info)) =
276 CumulusDigestItem::decode_all(&mut &val[..])
277 else {
278 return None
279 };
280
281 Some(core_info)
282 },
283 _ => None,
284 })
285 }
286
287 pub fn core_info_exists_at_max_once(digest: &Digest) -> CoreInfoExistsAtMaxOnce {
290 let mut core_info = None;
291 if digest
292 .logs()
293 .iter()
294 .filter(|l| match l {
295 DigestItem::PreRuntime(CUMULUS_CONSENSUS_ID, d) => {
296 if let Ok(Self::CoreInfo(ci)) = Self::decode_all(&mut &d[..]) {
297 core_info = Some(ci);
298 true
299 } else {
300 false
301 }
302 },
303 _ => false,
304 })
305 .count() <= 1
306 {
307 core_info
308 .map(CoreInfoExistsAtMaxOnce::Once)
309 .unwrap_or(CoreInfoExistsAtMaxOnce::NotFound)
310 } else {
311 CoreInfoExistsAtMaxOnce::MoreThanOnce
312 }
313 }
314
315 pub fn find_relay_block_identifier(digest: &Digest) -> Option<RelayBlockIdentifier> {
319 digest.convert_first(|d| match d {
320 DigestItem::Consensus(id, val) if id == &CUMULUS_CONSENSUS_ID => {
321 let Ok(CumulusDigestItem::RelayParent(hash)) =
322 CumulusDigestItem::decode_all(&mut &val[..])
323 else {
324 return None
325 };
326
327 Some(RelayBlockIdentifier::ByHash(hash))
328 },
329 DigestItem::Consensus(id, val) if id == &rpsr_digest::RPSR_CONSENSUS_ID => {
330 let Ok((storage_root, block_number)) =
331 rpsr_digest::RpsrType::decode_all(&mut &val[..])
332 else {
333 return None
334 };
335
336 Some(RelayBlockIdentifier::ByStorageRoot {
337 storage_root,
338 block_number: block_number.into(),
339 })
340 },
341 _ => None,
342 })
343 }
344}
345
346pub fn extract_relay_parent(digest: &Digest) -> Option<relay_chain::Hash> {
350 digest.convert_first(|d| match d {
351 DigestItem::Consensus(id, val) if id == &CUMULUS_CONSENSUS_ID =>
352 match CumulusDigestItem::decode(&mut &val[..]) {
353 Ok(CumulusDigestItem::RelayParent(hash)) => Some(hash),
354 _ => None,
355 },
356 _ => None,
357 })
358}
359
360#[doc(hidden)]
377pub mod rpsr_digest {
378 use super::{relay_chain, ConsensusEngineId, DecodeAll, Digest, DigestItem, Encode};
379 use codec::Compact;
380
381 pub type RpsrType = (relay_chain::Hash, Compact<relay_chain::BlockNumber>);
383
384 pub const RPSR_CONSENSUS_ID: ConsensusEngineId = *b"RPSR";
386
387 pub fn relay_parent_storage_root_item(
389 storage_root: relay_chain::Hash,
390 number: impl Into<Compact<relay_chain::BlockNumber>>,
391 ) -> DigestItem {
392 DigestItem::Consensus(
393 RPSR_CONSENSUS_ID,
394 RpsrType::from((storage_root, number.into())).encode(),
395 )
396 }
397
398 pub fn extract_relay_parent_storage_root(
401 digest: &Digest,
402 ) -> Option<(relay_chain::Hash, relay_chain::BlockNumber)> {
403 digest.convert_first(|d| match d {
404 DigestItem::Consensus(id, val) if id == &RPSR_CONSENSUS_ID => {
405 let (h, n) = RpsrType::decode_all(&mut &val[..]).ok()?;
406
407 Some((h, n.0))
408 },
409 _ => None,
410 })
411 }
412}
413
414#[derive(Clone, Debug, codec::Decode, codec::Encode, PartialEq)]
418pub struct CollationInfoV1 {
419 pub upward_messages: Vec<UpwardMessage>,
421 pub horizontal_messages: Vec<OutboundHrmpMessage>,
423 pub new_validation_code: Option<relay_chain::ValidationCode>,
425 pub processed_downward_messages: u32,
427 pub hrmp_watermark: relay_chain::BlockNumber,
430}
431
432impl CollationInfoV1 {
433 pub fn into_latest(self, head_data: HeadData) -> CollationInfo {
435 CollationInfo {
436 upward_messages: self.upward_messages,
437 horizontal_messages: self.horizontal_messages,
438 new_validation_code: self.new_validation_code,
439 processed_downward_messages: self.processed_downward_messages,
440 hrmp_watermark: self.hrmp_watermark,
441 head_data,
442 }
443 }
444}
445
446#[derive(Clone, Debug, codec::Decode, codec::Encode, PartialEq, TypeInfo)]
448pub struct CollationInfo {
449 pub upward_messages: Vec<UpwardMessage>,
451 pub horizontal_messages: Vec<OutboundHrmpMessage>,
453 pub new_validation_code: Option<relay_chain::ValidationCode>,
455 pub processed_downward_messages: u32,
457 pub hrmp_watermark: relay_chain::BlockNumber,
460 pub head_data: HeadData,
462}
463
464sp_api::decl_runtime_apis! {
465 #[api_version(3)]
471 pub trait CollectCollationInfo {
472 #[changed_in(2)]
474 fn collect_collation_info() -> CollationInfoV1;
475 fn collect_collation_info(header: &Block::Header) -> CollationInfo;
480 }
481
482 pub trait GetParachainInfo {
484 fn parachain_id() -> ParaId;
486 }
487
488 pub trait RelayParentOffsetApi {
493 fn relay_parent_offset() -> u32;
495 }
496}