// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Pezkuwi. // Pezkuwi is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Pezkuwi is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Pezkuwi. If not, see . //! Simple mock message queue. use codec::{Decode, Encode}; use pezkuwi_primitives::BlockNumber as RelayBlockNumber; use pezkuwi_teyrchain_primitives::primitives::{ DmpMessageHandler, Id as ParaId, XcmpMessageFormat, XcmpMessageHandler, }; use pezsp_runtime::traits::{Get, Hash}; use xcm::{latest::prelude::*, VersionedXcm}; pub use pezpallet::*; #[pezframe_support::pezpallet] pub mod pezpallet { use super::*; use pezframe_support::pezpallet_prelude::*; #[pezpallet::config] pub trait Config: pezframe_system::Config { #[allow(deprecated)] type RuntimeEvent: From> + IsType<::RuntimeEvent>; type XcmExecutor: ExecuteXcm; } #[pezpallet::call] impl Pezpallet {} #[pezpallet::pezpallet] #[pezpallet::without_storage_info] pub struct Pezpallet(_); #[pezpallet::storage] pub type TeyrchainId = StorageValue<_, ParaId, ValueQuery>; #[pezpallet::storage] /// A queue of received DMP messages pub type ReceivedDmp = StorageValue<_, Vec>, ValueQuery>; impl Get for Pezpallet { fn get() -> ParaId { TeyrchainId::::get() } } pub type MessageId = [u8; 32]; #[pezpallet::event] #[pezpallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { // XCMP /// Some XCM was executed OK. Success { message_id: Option }, /// Some XCM failed. Fail { message_id: Option, error: XcmError }, /// Bad XCM version used. BadVersion { message_id: Option }, /// Bad XCM format used. BadFormat { message_id: Option }, // DMP /// Downward message is invalid XCM. InvalidFormat { message_id: MessageId }, /// Downward message is unsupported version of XCM. UnsupportedVersion { message_id: MessageId }, /// Downward message executed with the given outcome. ExecutedDownward { message_id: MessageId, outcome: Outcome }, } impl Pezpallet { pub fn set_para_id(para_id: ParaId) { TeyrchainId::::put(para_id); } fn handle_xcmp_message( sender: ParaId, _sent_at: RelayBlockNumber, xcm: VersionedXcm, max_weight: xcm::latest::Weight, ) -> Result { let hash = Encode::using_encoded(&xcm, T::Hashing::hash); let mut message_hash = Encode::using_encoded(&xcm, pezsp_io::hashing::blake2_256); let (result, event) = match Xcm::::try_from(xcm) { Ok(xcm) => { let location = (Parent, Teyrchain(sender.into())); match T::XcmExecutor::prepare_and_execute( location, xcm, &mut message_hash, max_weight, Weight::zero(), ) { Outcome::Error(InstructionError { error, .. }) => { (Err(error), Event::Fail { message_id: Some(hash), error }) }, Outcome::Complete { used } => { (Ok(used), Event::Success { message_id: Some(hash) }) }, // As far as the caller is concerned, this was dispatched without error, so // we just report the weight used. Outcome::Incomplete { used, error: InstructionError { error, .. }, .. } => (Ok(used), Event::Fail { message_id: Some(hash), error }), } }, Err(()) => ( Err(XcmError::UnhandledXcmVersion), Event::BadVersion { message_id: Some(hash) }, ), }; Self::deposit_event(event); result } } impl XcmpMessageHandler for Pezpallet { fn handle_xcmp_messages<'a, I: Iterator>( iter: I, max_weight: xcm::latest::Weight, ) -> xcm::latest::Weight { for (sender, sent_at, data) in iter { let mut data_ref = data; let _ = XcmpMessageFormat::decode(&mut data_ref) .expect("Simulator encodes with versioned xcm format; qed"); let mut remaining_fragments = data_ref; while !remaining_fragments.is_empty() { if let Ok(xcm) = VersionedXcm::::decode(&mut remaining_fragments) { let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); } else { debug_assert!(false, "Invalid incoming XCMP message data"); } } } max_weight } } impl DmpMessageHandler for Pezpallet { fn handle_dmp_messages( iter: impl Iterator)>, limit: Weight, ) -> Weight { for (_sent_at, data) in iter { let mut id = pezsp_io::hashing::blake2_256(&data[..]); let maybe_versioned = VersionedXcm::::decode(&mut &data[..]); match maybe_versioned { Err(_) => { Self::deposit_event(Event::InvalidFormat { message_id: id }); }, Ok(versioned) => match Xcm::try_from(versioned) { Err(()) => { Self::deposit_event(Event::UnsupportedVersion { message_id: id }) }, Ok(x) => { let outcome = T::XcmExecutor::prepare_and_execute( Parent, x.clone(), &mut id, limit, Weight::zero(), ); ReceivedDmp::::append(x); Self::deposit_event(Event::ExecutedDownward { message_id: id, outcome, }); }, }, } } limit } } }