1#![warn(missing_docs)]
20#![cfg_attr(not(feature = "std"), no_std)]
21
22use codec::{Decode, DecodeWithMemTracking, Encode, FullCodec, MaxEncodedLen};
23use pezframe_support::{
24 pezpallet_prelude::DispatchResult, weights::Weight, PalletError, StorageHasher, StorageValue,
25};
26use pezframe_system::RawOrigin;
27use pezsp_core::storage::StorageKey;
28use pezsp_runtime::{
29 traits::{BadOrigin, Header as HeaderT, UniqueSaturatedInto},
30 RuntimeDebug,
31};
32use pezsp_std::{fmt::Debug, ops::RangeInclusive, vec, vec::Vec};
33use scale_info::TypeInfo;
34use serde::{Deserialize, Serialize};
35
36pub use chain::{
37 AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf,
38 HasherOf, HeaderOf, NonceOf, SignatureOf, Teyrchain, TeyrchainIdOf, TransactionEraOf,
39 UnderlyingChainOf, UnderlyingChainProvider, __private,
40};
41use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero};
42pub use pezframe_support::storage::storage_prefix as storage_value_final_key;
43#[cfg(feature = "std")]
44pub use storage_proof::craft_valid_storage_proof;
45#[cfg(feature = "test-helpers")]
46pub use storage_proof::{
47 grow_storage_proof, grow_storage_value, record_all_keys as record_all_trie_keys,
48 UnverifiedStorageProofParams,
49};
50pub use storage_proof::{
51 raw_storage_proof_size, RawStorageProof, StorageProofChecker, StorageProofError,
52};
53pub use storage_types::BoundedStorageValue;
54
55extern crate alloc;
56
57pub mod extensions;
58pub mod messages;
59
60mod chain;
61mod storage_proof;
62mod storage_types;
63
64pub use pezsp_runtime::paste;
66
67#[doc(hidden)]
69pub mod private {
70 #[doc(hidden)]
71 pub use alloc::vec::Vec;
72}
73
74pub const NO_INSTANCE_ID: ChainId = [0, 0, 0, 0];
76
77#[derive(
79 RuntimeDebug,
80 Default,
81 Clone,
82 Encode,
83 Decode,
84 Copy,
85 Eq,
86 Hash,
87 MaxEncodedLen,
88 PartialEq,
89 PartialOrd,
90 Ord,
91 TypeInfo,
92)]
93pub struct HeaderId<Hash, Number>(pub Number, pub Hash);
94
95impl<Hash: Copy, Number: Copy> HeaderId<Hash, Number> {
96 pub fn number(&self) -> Number {
98 self.0
99 }
100
101 pub fn hash(&self) -> Hash {
103 self.1
104 }
105}
106
107pub type HeaderIdOf<C> = HeaderId<HashOf<C>, BlockNumberOf<C>>;
109
110pub trait HeaderIdProvider<Header: HeaderT> {
112 fn id(&self) -> HeaderId<Header::Hash, Header::Number>;
114
115 fn parent_id(&self) -> Option<HeaderId<Header::Hash, Header::Number>>;
117}
118
119impl<Header: HeaderT> HeaderIdProvider<Header> for Header {
120 fn id(&self) -> HeaderId<Header::Hash, Header::Number> {
121 HeaderId(*self.number(), self.hash())
122 }
123
124 fn parent_id(&self) -> Option<HeaderId<Header::Hash, Header::Number>> {
125 self.number()
126 .checked_sub(&One::one())
127 .map(|parent_number| HeaderId(parent_number, *self.parent_hash()))
128 }
129}
130
131pub type ChainId = [u8; 4];
139
140pub trait Size {
142 fn size(&self) -> u32;
144}
145
146impl Size for () {
147 fn size(&self) -> u32 {
148 0
149 }
150}
151
152impl Size for Vec<u8> {
153 fn size(&self) -> u32 {
154 self.len() as _
155 }
156}
157
158pub struct PreComputedSize(pub usize);
160
161impl Size for PreComputedSize {
162 fn size(&self) -> u32 {
163 u32::try_from(self.0).unwrap_or(u32::MAX)
164 }
165}
166
167#[derive(RuntimeDebug, Clone, Copy, PartialEq)]
169pub enum TransactionEra<BlockNumber, BlockHash> {
170 Immortal,
172 Mortal(HeaderId<BlockHash, BlockNumber>, u32),
174}
175
176impl<BlockNumber: Copy + UniqueSaturatedInto<u64>, BlockHash: Copy>
177 TransactionEra<BlockNumber, BlockHash>
178{
179 pub fn new(
181 best_block_id: HeaderId<BlockHash, BlockNumber>,
182 mortality_period: Option<u32>,
183 ) -> Self {
184 mortality_period
185 .map(|mortality_period| TransactionEra::Mortal(best_block_id, mortality_period))
186 .unwrap_or(TransactionEra::Immortal)
187 }
188
189 pub fn immortal() -> Self {
191 TransactionEra::Immortal
192 }
193
194 pub fn mortality_period(&self) -> Option<u32> {
196 match *self {
197 TransactionEra::Immortal => None,
198 TransactionEra::Mortal(_, period) => Some(period),
199 }
200 }
201
202 pub fn frame_era(&self) -> pezsp_runtime::generic::Era {
204 match *self {
205 TransactionEra::Immortal => pezsp_runtime::generic::Era::immortal(),
206 TransactionEra::Mortal(header_id, period) => pezsp_runtime::generic::Era::mortal(
209 period as _,
210 header_id.0.unique_saturated_into(),
211 ),
212 }
213 }
214
215 pub fn signed_payload(&self, genesis_hash: BlockHash) -> BlockHash {
217 match *self {
218 TransactionEra::Immortal => genesis_hash,
219 TransactionEra::Mortal(header_id, _) => header_id.1,
220 }
221 }
222}
223
224pub fn storage_map_final_key<H: StorageHasher>(
231 pezpallet_prefix: &str,
232 map_name: &str,
233 key: &[u8],
234) -> StorageKey {
235 let key_hashed = H::hash(key);
236 let pezpallet_prefix_hashed = pezframe_support::Twox128::hash(pezpallet_prefix.as_bytes());
237 let storage_prefix_hashed = pezframe_support::Twox128::hash(map_name.as_bytes());
238
239 let mut final_key = Vec::with_capacity(
240 pezpallet_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len(),
241 );
242
243 final_key.extend_from_slice(&pezpallet_prefix_hashed[..]);
244 final_key.extend_from_slice(&storage_prefix_hashed[..]);
245 final_key.extend_from_slice(key_hashed.as_ref());
246
247 StorageKey(final_key)
248}
249
250pub fn storage_value_key(pezpallet_prefix: &str, value_name: &str) -> StorageKey {
254 let pezpallet_hash = pezsp_io::hashing::twox_128(pezpallet_prefix.as_bytes());
255 let storage_hash = pezsp_io::hashing::twox_128(value_name.as_bytes());
256
257 let mut final_key = vec![0u8; 32];
258 final_key[..16].copy_from_slice(&pezpallet_hash);
259 final_key[16..].copy_from_slice(&storage_hash);
260
261 StorageKey(final_key)
262}
263
264pub trait StorageMapKeyProvider {
266 const MAP_NAME: &'static str;
268
269 type Hasher: StorageHasher;
271 type Key: FullCodec + Send + Sync;
273 type Value: 'static + FullCodec;
275
276 fn final_key(pezpallet_prefix: &str, key: &Self::Key) -> StorageKey {
282 storage_map_final_key::<Self::Hasher>(pezpallet_prefix, Self::MAP_NAME, &key.encode())
283 }
284}
285
286pub trait StorageDoubleMapKeyProvider {
288 const MAP_NAME: &'static str;
290
291 type Hasher1: StorageHasher;
293 type Key1: FullCodec + Send + Sync;
295 type Hasher2: StorageHasher;
297 type Key2: FullCodec + Send + Sync;
299 type Value: 'static + FullCodec;
301
302 fn final_key(pezpallet_prefix: &str, key1: &Self::Key1, key2: &Self::Key2) -> StorageKey {
308 let key1_hashed = Self::Hasher1::hash(&key1.encode());
309 let key2_hashed = Self::Hasher2::hash(&key2.encode());
310 let pezpallet_prefix_hashed = pezframe_support::Twox128::hash(pezpallet_prefix.as_bytes());
311 let storage_prefix_hashed = pezframe_support::Twox128::hash(Self::MAP_NAME.as_bytes());
312
313 let mut final_key = Vec::with_capacity(
314 pezpallet_prefix_hashed.len()
315 + storage_prefix_hashed.len()
316 + key1_hashed.as_ref().len()
317 + key2_hashed.as_ref().len(),
318 );
319
320 final_key.extend_from_slice(&pezpallet_prefix_hashed[..]);
321 final_key.extend_from_slice(&storage_prefix_hashed[..]);
322 final_key.extend_from_slice(key1_hashed.as_ref());
323 final_key.extend_from_slice(key2_hashed.as_ref());
324
325 StorageKey(final_key)
326 }
327}
328
329#[derive(Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo, PalletError)]
331pub enum OwnedBridgeModuleError {
332 Halted,
334}
335
336pub trait OperatingMode: Send + Copy + Debug + FullCodec {
338 fn is_halted(&self) -> bool;
340}
341
342#[derive(
344 Encode,
345 Decode,
346 DecodeWithMemTracking,
347 Clone,
348 Copy,
349 PartialEq,
350 Eq,
351 RuntimeDebug,
352 TypeInfo,
353 MaxEncodedLen,
354 Serialize,
355 Deserialize,
356)]
357pub enum BasicOperatingMode {
358 Normal,
360 Halted,
362}
363
364impl Default for BasicOperatingMode {
365 fn default() -> Self {
366 Self::Normal
367 }
368}
369
370impl OperatingMode for BasicOperatingMode {
371 fn is_halted(&self) -> bool {
372 *self == BasicOperatingMode::Halted
373 }
374}
375
376const COMMON_LOG_TARGET: &'static str = "runtime::bridge-module";
377
378pub trait OwnedBridgeModule<T: pezframe_system::Config> {
380 const LOG_TARGET: &'static str;
382
383 type OwnerStorage: StorageValue<T::AccountId, Query = Option<T::AccountId>>;
385 type OperatingMode: OperatingMode;
387 type OperatingModeStorage: StorageValue<Self::OperatingMode, Query = Self::OperatingMode>;
389
390 fn is_halted() -> bool {
392 Self::OperatingModeStorage::get().is_halted()
393 }
394
395 fn ensure_owner_or_root(origin: T::RuntimeOrigin) -> Result<(), BadOrigin> {
397 match origin.into() {
398 Ok(RawOrigin::Root) => Ok(()),
399 Ok(RawOrigin::Signed(ref signer))
400 if Self::OwnerStorage::get().as_ref() == Some(signer) =>
401 {
402 Ok(())
403 },
404 _ => Err(BadOrigin),
405 }
406 }
407
408 fn ensure_not_halted() -> Result<(), OwnedBridgeModuleError> {
410 match Self::is_halted() {
411 true => Err(OwnedBridgeModuleError::Halted),
412 false => Ok(()),
413 }
414 }
415
416 fn set_owner(origin: T::RuntimeOrigin, maybe_owner: Option<T::AccountId>) -> DispatchResult {
418 Self::ensure_owner_or_root(origin)?;
419 match maybe_owner {
420 Some(owner) => {
421 Self::OwnerStorage::put(&owner);
422 tracing::info!(target: COMMON_LOG_TARGET, module=%Self::LOG_TARGET, ?owner, "Setting pezpallet.");
423 },
424 None => {
425 Self::OwnerStorage::kill();
426 tracing::info!(target: COMMON_LOG_TARGET, module=%Self::LOG_TARGET, "Removed Owner of pezpallet.");
427 },
428 }
429
430 Ok(())
431 }
432
433 fn set_operating_mode(
435 origin: T::RuntimeOrigin,
436 operating_mode: Self::OperatingMode,
437 ) -> DispatchResult {
438 Self::ensure_owner_or_root(origin)?;
439 Self::OperatingModeStorage::put(operating_mode);
440 tracing::info!(target: COMMON_LOG_TARGET, module=%Self::LOG_TARGET, ?operating_mode, "Setting operating mode.");
441 Ok(())
442 }
443
444 fn module_owner() -> Option<T::AccountId> {
449 Self::OwnerStorage::get()
450 }
451
452 fn operating_mode() -> Self::OperatingMode {
455 Self::OperatingModeStorage::get()
456 }
457}
458
459pub trait WeightExtraOps {
461 fn min_components_checked_div(&self, other: Weight) -> Option<u64>;
466}
467
468impl WeightExtraOps for Weight {
469 fn min_components_checked_div(&self, other: Weight) -> Option<u64> {
470 Some(pezsp_std::cmp::min(
471 self.ref_time().checked_div(other.ref_time())?,
472 self.proof_size().checked_div(other.proof_size())?,
473 ))
474 }
475}
476
477pub trait StaticStrProvider {
479 const STR: &'static str;
481}
482
483#[macro_export]
485macro_rules! generate_static_str_provider {
486 ($str:expr) => {
487 $crate::paste::item! {
488 pub struct [<Str $str>];
489
490 impl $crate::StaticStrProvider for [<Str $str>] {
491 const STR: &'static str = stringify!($str);
492 }
493 }
494 };
495}
496
497pub trait RangeInclusiveExt<Idx> {
499 fn checked_len(&self) -> Option<Idx>;
501 fn saturating_len(&self) -> Idx;
503}
504
505impl<Idx> RangeInclusiveExt<Idx> for RangeInclusive<Idx>
506where
507 Idx: CheckedSub + CheckedAdd + SaturatingAdd + One + Zero,
508{
509 fn checked_len(&self) -> Option<Idx> {
510 self.end()
511 .checked_sub(self.start())
512 .and_then(|len| len.checked_add(&Idx::one()))
513 }
514
515 fn saturating_len(&self) -> Idx {
516 let len = match self.end().checked_sub(self.start()) {
517 Some(len) => len,
518 None => return Idx::zero(),
519 };
520 len.saturating_add(&Idx::one())
521 }
522}
523
524#[cfg(test)]
525mod tests {
526 use super::*;
527
528 #[test]
529 fn storage_value_key_works() {
530 assert_eq!(
531 storage_value_key("PalletTransactionPayment", "NextFeeMultiplier"),
532 StorageKey(
533 hex_literal::hex!(
534 "f0e954dfcca51a255ab12c60c789256a3f2edf3bdf381debe331ab7446addfdc"
535 )
536 .to_vec()
537 ),
538 );
539 }
540
541 #[test]
542 fn generate_static_str_provider_works() {
543 generate_static_str_provider!(Test);
544 assert_eq!(StrTest::STR, "Test");
545 }
546}