pezsp_runtime/
lib.rs

1// This file is part of Bizinikiwi.
2
3// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Bizinikiwi Runtime Primitives.
19//!
20//! This crate, among other things, contains a large library of types and utilities that are used in
21//! the Bizinikiwi runtime, but are not particularly `FRAME`-oriented.
22//!
23//! ## Block, Header and Extrinsics
24//!
25//! Most notable, this crate contains some of the types and trait that enable important
26//! communication between the client and the runtime. This includes:
27//!
28//! - A set of traits to declare what any block/header/extrinsic type should provide.
29//! 	- [`traits::Block`], [`traits::Header`], [`traits::ExtrinsicLike`]
30//! - A set of types that implement these traits, whilst still providing a high degree of
31//!   configurability via generics.
32//! 	- [`generic::Block`], [`generic::Header`], [`generic::UncheckedExtrinsic`] and
33//!    [`generic::CheckedExtrinsic`]
34//!
35//! ## Runtime API Types
36//!
37//! This crate also contains some types that are often used in conjuncture with Runtime APIs. Most
38//! notable:
39//!
40//! - [`ApplyExtrinsicResult`], and [`DispatchOutcome`], which dictate how the client and runtime
41//!   communicate about the success or failure of an extrinsic.
42//! - [`transaction_validity`], which dictates how the client and runtime communicate about the
43//!  validity of an extrinsic while still in the transaction-queue.
44
45#![warn(missing_docs)]
46#![cfg_attr(not(feature = "std"), no_std)]
47
48#[doc(hidden)]
49extern crate alloc;
50
51#[doc(hidden)]
52pub use alloc::vec::Vec;
53#[doc(hidden)]
54pub use codec;
55#[doc(hidden)]
56pub use pezsp_std;
57#[doc(hidden)]
58pub use scale_info;
59#[cfg(feature = "serde")]
60#[doc(hidden)]
61pub use serde;
62
63#[doc(hidden)]
64pub use paste;
65#[doc(hidden)]
66pub use pezsp_arithmetic::traits::Saturating;
67
68#[doc(hidden)]
69pub use pezsp_application_crypto as app_crypto;
70
71pub use pezsp_core::storage::StateVersion;
72#[cfg(feature = "std")]
73pub use pezsp_core::storage::{Storage, StorageChild};
74
75use pezsp_core::{
76	crypto::{self, ByteArray, FromEntropy},
77	ecdsa, ed25519,
78	hash::{H256, H512},
79	sr25519,
80};
81
82use alloc::vec;
83use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
84use scale_info::TypeInfo;
85
86pub mod curve;
87pub mod generic;
88pub mod legacy;
89mod multiaddress;
90pub mod offchain;
91pub mod proving_trie;
92pub mod runtime_logger;
93#[cfg(feature = "std")]
94pub mod testing;
95pub mod traits;
96pub mod transaction_validity;
97pub mod type_with_default;
98
99// Re-export Multiaddress
100pub use multiaddress::MultiAddress;
101
102use proving_trie::TrieError;
103
104/// Re-export these since they're only "kind of" generic.
105pub use generic::{Digest, DigestItem};
106
107pub use pezsp_application_crypto::{BoundToRuntimeAppPublic, RuntimeAppPublic};
108/// Re-export this since it's part of the API of this crate.
109pub use pezsp_core::{
110	bounded::{BoundedBTreeMap, BoundedBTreeSet, BoundedSlice, BoundedVec, WeakBoundedVec},
111	crypto::{key_types, AccountId32, CryptoType, CryptoTypeId, KeyTypeId},
112	TypeId,
113};
114/// Re-export bounded_vec and bounded_btree_map macros only when std is enabled.
115#[cfg(feature = "std")]
116pub use pezsp_core::{bounded_btree_map, bounded_vec};
117
118/// Re-export `RuntimeDebug`, to avoid dependency clutter.
119pub use pezsp_core::RuntimeDebug;
120
121/// Re-export big_uint stuff.
122pub use pezsp_arithmetic::biguint;
123/// Re-export 128 bit helpers.
124pub use pezsp_arithmetic::helpers_128bit;
125/// Re-export top-level arithmetic stuff.
126pub use pezsp_arithmetic::{
127	traits::SaturatedConversion, ArithmeticError, FixedI128, FixedI64, FixedPointNumber,
128	FixedPointOperand, FixedU128, FixedU64, InnerOf, PerThing, PerU16, Perbill, Percent, Permill,
129	Perquintill, Rational128, Rounding, UpperOf,
130};
131/// Re-export this since it's part of the API of this crate.
132pub use pezsp_weights::Weight;
133
134pub use either::Either;
135
136/// The number of bytes of the module-specific `error` field defined in [`ModuleError`].
137/// In FRAME, this is the maximum encoded size of a pezpallet error type.
138pub const MAX_MODULE_ERROR_ENCODED_SIZE: usize = 4;
139
140/// An abstraction over justification for a block's validity under a consensus algorithm.
141///
142/// Essentially a finality proof. The exact formulation will vary between consensus
143/// algorithms. In the case where there are multiple valid proofs, inclusion within
144/// the block itself would allow swapping justifications to change the block's hash
145/// (and thus fork the chain). Sending a `Justification` alongside a block instead
146/// bypasses this problem.
147///
148/// Each justification is provided as an encoded blob, and is tagged with an ID
149/// to identify the consensus engine that generated the proof (we might have
150/// multiple justifications from different engines for the same block).
151pub type Justification = (ConsensusEngineId, EncodedJustification);
152
153/// The encoded justification specific to a consensus engine.
154pub type EncodedJustification = Vec<u8>;
155
156/// Collection of justifications for a given block, multiple justifications may
157/// be provided by different consensus engines for the same block.
158#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
159#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)]
160pub struct Justifications(Vec<Justification>);
161
162impl Justifications {
163	/// Create a new `Justifications` instance with the given justifications.
164	pub fn new(justifications: Vec<Justification>) -> Self {
165		Self(justifications)
166	}
167
168	/// Return an iterator over the justifications.
169	pub fn iter(&self) -> impl Iterator<Item = &Justification> {
170		self.0.iter()
171	}
172
173	/// Append a justification. Returns false if a justification with the same
174	/// `ConsensusEngineId` already exists, in which case the justification is
175	/// not inserted.
176	pub fn append(&mut self, justification: Justification) -> bool {
177		if self.get(justification.0).is_some() {
178			return false;
179		}
180		self.0.push(justification);
181		true
182	}
183
184	/// Return the encoded justification for the given consensus engine, if it
185	/// exists.
186	pub fn get(&self, engine_id: ConsensusEngineId) -> Option<&EncodedJustification> {
187		self.iter().find(|j| j.0 == engine_id).map(|j| &j.1)
188	}
189
190	/// Remove the encoded justification for the given consensus engine, if it exists.
191	pub fn remove(&mut self, engine_id: ConsensusEngineId) {
192		self.0.retain(|j| j.0 != engine_id)
193	}
194
195	/// Return a copy of the encoded justification for the given consensus
196	/// engine, if it exists.
197	pub fn into_justification(self, engine_id: ConsensusEngineId) -> Option<EncodedJustification> {
198		self.into_iter().find(|j| j.0 == engine_id).map(|j| j.1)
199	}
200}
201
202impl IntoIterator for Justifications {
203	type Item = Justification;
204	type IntoIter = alloc::vec::IntoIter<Self::Item>;
205
206	fn into_iter(self) -> Self::IntoIter {
207		self.0.into_iter()
208	}
209}
210
211impl From<Justification> for Justifications {
212	fn from(justification: Justification) -> Self {
213		Self(vec![justification])
214	}
215}
216
217use traits::{Lazy, Verify};
218
219use crate::traits::{IdentifyAccount, LazyExtrinsic};
220#[cfg(feature = "serde")]
221pub use serde::{de::DeserializeOwned, Deserialize, Serialize};
222
223/// Complex storage builder stuff.
224#[cfg(feature = "std")]
225pub trait BuildStorage {
226	/// Build the storage out of this builder.
227	fn build_storage(&self) -> Result<pezsp_core::storage::Storage, String> {
228		let mut storage = Default::default();
229		self.assimilate_storage(&mut storage)?;
230		Ok(storage)
231	}
232	/// Assimilate the storage for this module into pre-existing overlays.
233	fn assimilate_storage(&self, storage: &mut pezsp_core::storage::Storage) -> Result<(), String>;
234}
235
236/// Something that can build the genesis storage of a module.
237#[cfg(feature = "std")]
238#[deprecated(
239	note = "`BuildModuleGenesisStorage` is planned to be removed in December 2023. Use `BuildStorage` instead of it."
240)]
241pub trait BuildModuleGenesisStorage<T, I>: Sized {
242	/// Create the module genesis storage into the given `storage` and `child_storage`.
243	fn build_module_genesis_storage(
244		&self,
245		storage: &mut pezsp_core::storage::Storage,
246	) -> Result<(), String>;
247}
248
249#[cfg(feature = "std")]
250impl BuildStorage for pezsp_core::storage::Storage {
251	fn assimilate_storage(&self, storage: &mut pezsp_core::storage::Storage) -> Result<(), String> {
252		storage.top.extend(self.top.iter().map(|(k, v)| (k.clone(), v.clone())));
253		for (k, other_map) in self.children_default.iter() {
254			let k = k.clone();
255			if let Some(map) = storage.children_default.get_mut(&k) {
256				map.data.extend(other_map.data.iter().map(|(k, v)| (k.clone(), v.clone())));
257				if !map.child_info.try_update(&other_map.child_info) {
258					return Err("Incompatible child info update".to_string());
259				}
260			} else {
261				storage.children_default.insert(k, other_map.clone());
262			}
263		}
264		Ok(())
265	}
266}
267
268#[cfg(feature = "std")]
269impl BuildStorage for () {
270	fn assimilate_storage(&self, _: &mut pezsp_core::storage::Storage) -> Result<(), String> {
271		Err("`assimilate_storage` not implemented for `()`".into())
272	}
273}
274
275/// Consensus engine unique ID.
276pub type ConsensusEngineId = [u8; 4];
277
278/// Signature verify that can work with any known signature types.
279#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
280#[derive(
281	Eq,
282	PartialEq,
283	Clone,
284	Encode,
285	Decode,
286	DecodeWithMemTracking,
287	MaxEncodedLen,
288	RuntimeDebug,
289	TypeInfo,
290)]
291pub enum MultiSignature {
292	/// An Ed25519 signature.
293	Ed25519(ed25519::Signature),
294	/// An Sr25519 signature.
295	Sr25519(sr25519::Signature),
296	/// An ECDSA/SECP256k1 signature.
297	Ecdsa(ecdsa::Signature),
298	/// An ECDSA/SECP256k1 signature but with a different address derivation.
299	Eth(ecdsa::KeccakSignature),
300}
301
302impl From<ed25519::Signature> for MultiSignature {
303	fn from(x: ed25519::Signature) -> Self {
304		Self::Ed25519(x)
305	}
306}
307
308impl TryFrom<MultiSignature> for ed25519::Signature {
309	type Error = ();
310	fn try_from(m: MultiSignature) -> Result<Self, Self::Error> {
311		if let MultiSignature::Ed25519(x) = m {
312			Ok(x)
313		} else {
314			Err(())
315		}
316	}
317}
318
319impl From<sr25519::Signature> for MultiSignature {
320	fn from(x: sr25519::Signature) -> Self {
321		Self::Sr25519(x)
322	}
323}
324
325impl TryFrom<MultiSignature> for sr25519::Signature {
326	type Error = ();
327	fn try_from(m: MultiSignature) -> Result<Self, Self::Error> {
328		if let MultiSignature::Sr25519(x) = m {
329			Ok(x)
330		} else {
331			Err(())
332		}
333	}
334}
335
336impl From<ecdsa::Signature> for MultiSignature {
337	fn from(x: ecdsa::Signature) -> Self {
338		Self::Ecdsa(x)
339	}
340}
341
342impl TryFrom<MultiSignature> for ecdsa::Signature {
343	type Error = ();
344	fn try_from(m: MultiSignature) -> Result<Self, Self::Error> {
345		if let MultiSignature::Ecdsa(x) = m {
346			Ok(x)
347		} else {
348			Err(())
349		}
350	}
351}
352
353/// Public key for any known crypto algorithm.
354#[derive(
355	Eq,
356	PartialEq,
357	Ord,
358	PartialOrd,
359	Clone,
360	Encode,
361	Decode,
362	DecodeWithMemTracking,
363	RuntimeDebug,
364	TypeInfo,
365)]
366#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
367pub enum MultiSigner {
368	/// An Ed25519 identity.
369	Ed25519(ed25519::Public),
370	/// An Sr25519 identity.
371	Sr25519(sr25519::Public),
372	/// An SECP256k1/ECDSA identity (actually, the Blake2 hash of the compressed pub key).
373	Ecdsa(ecdsa::Public),
374	/// Same as `Ecdsa` but its account id is derived based off its eth address instead of its
375	/// pubkey.
376	///
377	/// This is important so that the address matches the address to address mapping in
378	/// `pezpallet_revive`. This means that the same public key controls two accounts. But
379	/// this is already the case due to `pezpallet_revive`'s address mapping.
380	Eth(ecdsa::KeccakPublic),
381}
382
383impl FromEntropy for MultiSigner {
384	fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
385		Ok(match input.read_byte()? % 4 {
386			0 => Self::Ed25519(FromEntropy::from_entropy(input)?),
387			1 => Self::Sr25519(FromEntropy::from_entropy(input)?),
388			2 => Self::Ecdsa(FromEntropy::from_entropy(input)?),
389			3.. => Self::Eth(FromEntropy::from_entropy(input)?),
390		})
391	}
392}
393
394/// NOTE: This implementations is required by `SimpleAddressDeterminer`,
395/// we convert the hash into some AccountId, it's fine to use any scheme.
396impl<T: Into<H256>> crypto::UncheckedFrom<T> for MultiSigner {
397	fn unchecked_from(x: T) -> Self {
398		ed25519::Public::unchecked_from(x.into()).into()
399	}
400}
401
402impl AsRef<[u8]> for MultiSigner {
403	fn as_ref(&self) -> &[u8] {
404		match *self {
405			Self::Ed25519(ref who) => who.as_ref(),
406			Self::Sr25519(ref who) => who.as_ref(),
407			Self::Ecdsa(ref who) => who.as_ref(),
408			Self::Eth(ref who) => who.as_ref(),
409		}
410	}
411}
412
413impl traits::IdentifyAccount for MultiSigner {
414	type AccountId = AccountId32;
415	fn into_account(self) -> AccountId32 {
416		match self {
417			Self::Ed25519(who) => <[u8; 32]>::from(who).into(),
418			Self::Sr25519(who) => <[u8; 32]>::from(who).into(),
419			Self::Ecdsa(who) => pezsp_io::hashing::blake2_256(who.as_ref()).into(),
420			Self::Eth(who) => {
421				// It is important that the account id is based off the eth address rather
422				// than its pubkey. This is because in many cases we don't know the pubkey
423				// of an eth account.
424				let eth_address = &pezsp_io::hashing::keccak_256(who.as_ref())[12..];
425				// This is by convention: `pezpallet_revive` maps eth addresses to account ids
426				// by filling up the additional 12 bytes with 0xEE.
427				let mut address = [0xEE; 32];
428				address[..20].copy_from_slice(eth_address);
429				address.into()
430			},
431		}
432	}
433}
434
435impl From<ed25519::Public> for MultiSigner {
436	fn from(x: ed25519::Public) -> Self {
437		Self::Ed25519(x)
438	}
439}
440
441impl TryFrom<MultiSigner> for ed25519::Public {
442	type Error = ();
443	fn try_from(m: MultiSigner) -> Result<Self, Self::Error> {
444		if let MultiSigner::Ed25519(x) = m {
445			Ok(x)
446		} else {
447			Err(())
448		}
449	}
450}
451
452impl From<sr25519::Public> for MultiSigner {
453	fn from(x: sr25519::Public) -> Self {
454		Self::Sr25519(x)
455	}
456}
457
458impl TryFrom<MultiSigner> for sr25519::Public {
459	type Error = ();
460	fn try_from(m: MultiSigner) -> Result<Self, Self::Error> {
461		if let MultiSigner::Sr25519(x) = m {
462			Ok(x)
463		} else {
464			Err(())
465		}
466	}
467}
468
469impl From<ecdsa::Public> for MultiSigner {
470	fn from(x: ecdsa::Public) -> Self {
471		Self::Ecdsa(x)
472	}
473}
474
475impl TryFrom<MultiSigner> for ecdsa::Public {
476	type Error = ();
477	fn try_from(m: MultiSigner) -> Result<Self, Self::Error> {
478		if let MultiSigner::Ecdsa(x) = m {
479			Ok(x)
480		} else {
481			Err(())
482		}
483	}
484}
485
486#[cfg(feature = "std")]
487impl std::fmt::Display for MultiSigner {
488	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
489		match self {
490			Self::Ed25519(who) => write!(fmt, "ed25519: {}", who),
491			Self::Sr25519(who) => write!(fmt, "sr25519: {}", who),
492			Self::Ecdsa(who) => write!(fmt, "ecdsa: {}", who),
493			Self::Eth(who) => write!(fmt, "eth: {}", who),
494		}
495	}
496}
497
498impl Verify for MultiSignature {
499	type Signer = MultiSigner;
500	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &AccountId32) -> bool {
501		let who: [u8; 32] = *signer.as_ref();
502		match self {
503			Self::Ed25519(sig) => sig.verify(msg, &who.into()),
504			Self::Sr25519(sig) => sig.verify(msg, &who.into()),
505			Self::Ecdsa(sig) => {
506				let m = pezsp_io::hashing::blake2_256(msg.get());
507				pezsp_io::crypto::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m)
508					.map_or(false, |pubkey| pezsp_io::hashing::blake2_256(&pubkey) == who)
509			},
510			Self::Eth(sig) => {
511				let m = pezsp_io::hashing::keccak_256(msg.get());
512				pezsp_io::crypto::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m)
513					.map_or(false, |pubkey| {
514						&MultiSigner::Eth(pubkey.into()).into_account() == signer
515					})
516			},
517		}
518	}
519}
520
521/// Signature verify that can work with any known signature types..
522#[derive(Eq, PartialEq, Clone, Default, Encode, Decode, RuntimeDebug, TypeInfo)]
523#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
524pub struct AnySignature(H512);
525
526impl Verify for AnySignature {
527	type Signer = sr25519::Public;
528	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &sr25519::Public) -> bool {
529		let msg = msg.get();
530		sr25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
531			.map(|s| s.verify(msg, signer))
532			.unwrap_or(false)
533			|| ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
534				.map(|s| match ed25519::Public::from_slice(signer.as_ref()) {
535					Err(()) => false,
536					Ok(signer) => s.verify(msg, &signer),
537				})
538				.unwrap_or(false)
539	}
540}
541
542impl From<sr25519::Signature> for AnySignature {
543	fn from(s: sr25519::Signature) -> Self {
544		Self(s.into())
545	}
546}
547
548impl From<ed25519::Signature> for AnySignature {
549	fn from(s: ed25519::Signature) -> Self {
550		Self(s.into())
551	}
552}
553
554impl From<DispatchError> for DispatchOutcome {
555	fn from(err: DispatchError) -> Self {
556		Err(err)
557	}
558}
559
560/// This is the legacy return type of `Dispatchable`. It is still exposed for compatibility reasons.
561/// The new return type is `DispatchResultWithInfo`. FRAME runtimes should use
562/// `pezframe_support::dispatch::DispatchResult`.
563pub type DispatchResult = core::result::Result<(), DispatchError>;
564
565/// Return type of a `Dispatchable` which contains the `DispatchResult` and additional information
566/// about the `Dispatchable` that is only known post dispatch.
567pub type DispatchResultWithInfo<T> = core::result::Result<T, DispatchErrorWithPostInfo<T>>;
568
569/// Reason why a pezpallet call failed.
570#[derive(
571	Eq, Clone, Copy, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
572)]
573#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
574pub struct ModuleError {
575	/// Module index, matching the metadata module index.
576	pub index: u8,
577	/// Module specific error value.
578	pub error: [u8; MAX_MODULE_ERROR_ENCODED_SIZE],
579	/// Optional error message.
580	#[codec(skip)]
581	#[cfg_attr(feature = "serde", serde(skip_deserializing))]
582	pub message: Option<&'static str>,
583}
584
585impl PartialEq for ModuleError {
586	fn eq(&self, other: &Self) -> bool {
587		(self.index == other.index) && (self.error == other.error)
588	}
589}
590
591/// Errors related to transactional storage layers.
592#[derive(
593	Eq,
594	PartialEq,
595	Clone,
596	Copy,
597	Encode,
598	Decode,
599	DecodeWithMemTracking,
600	Debug,
601	TypeInfo,
602	MaxEncodedLen,
603)]
604#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
605pub enum TransactionalError {
606	/// Too many transactional layers have been spawned.
607	LimitReached,
608	/// A transactional layer was expected, but does not exist.
609	NoLayer,
610}
611
612impl From<TransactionalError> for &'static str {
613	fn from(e: TransactionalError) -> &'static str {
614		match e {
615			TransactionalError::LimitReached => "Too many transactional layers have been spawned",
616			TransactionalError::NoLayer => "A transactional layer was expected, but does not exist",
617		}
618	}
619}
620
621impl From<TransactionalError> for DispatchError {
622	fn from(e: TransactionalError) -> DispatchError {
623		Self::Transactional(e)
624	}
625}
626
627/// Reason why a dispatch call failed.
628#[derive(
629	Eq,
630	Clone,
631	Copy,
632	Encode,
633	Decode,
634	DecodeWithMemTracking,
635	Debug,
636	TypeInfo,
637	PartialEq,
638	MaxEncodedLen,
639)]
640#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
641pub enum DispatchError {
642	/// Some error occurred.
643	Other(
644		#[codec(skip)]
645		#[cfg_attr(feature = "serde", serde(skip_deserializing))]
646		&'static str,
647	),
648	/// Failed to lookup some data.
649	CannotLookup,
650	/// A bad origin.
651	BadOrigin,
652	/// A custom error in a module.
653	Module(ModuleError),
654	/// At least one consumer is remaining so the account cannot be destroyed.
655	ConsumerRemaining,
656	/// There are no providers so the account cannot be created.
657	NoProviders,
658	/// There are too many consumers so the account cannot be created.
659	TooManyConsumers,
660	/// An error to do with tokens.
661	Token(TokenError),
662	/// An arithmetic error.
663	Arithmetic(ArithmeticError),
664	/// The number of transactional layers has been reached, or we are not in a transactional
665	/// layer.
666	Transactional(TransactionalError),
667	/// Resources exhausted, e.g. attempt to read/write data which is too large to manipulate.
668	Exhausted,
669	/// The state is corrupt; this is generally not going to fix itself.
670	Corruption,
671	/// Some resource (e.g. a preimage) is unavailable right now. This might fix itself later.
672	Unavailable,
673	/// Root origin is not allowed.
674	RootNotAllowed,
675	/// An error with tries.
676	Trie(TrieError),
677}
678
679/// Result of a `Dispatchable` which contains the `DispatchResult` and additional information about
680/// the `Dispatchable` that is only known post dispatch.
681#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
682pub struct DispatchErrorWithPostInfo<Info>
683where
684	Info: Eq + PartialEq + Clone + Copy + Encode + Decode + traits::Printable,
685{
686	/// Additional information about the `Dispatchable` which is only known post dispatch.
687	pub post_info: Info,
688	/// The actual `DispatchResult` indicating whether the dispatch was successful.
689	pub error: DispatchError,
690}
691
692impl DispatchError {
693	/// Return the same error but without the attached message.
694	pub fn stripped(self) -> Self {
695		match self {
696			DispatchError::Module(ModuleError { index, error, message: Some(_) }) => {
697				DispatchError::Module(ModuleError { index, error, message: None })
698			},
699			m => m,
700		}
701	}
702}
703
704impl<T, E> From<E> for DispatchErrorWithPostInfo<T>
705where
706	T: Eq + PartialEq + Clone + Copy + Encode + Decode + traits::Printable + Default,
707	E: Into<DispatchError>,
708{
709	fn from(error: E) -> Self {
710		Self { post_info: Default::default(), error: error.into() }
711	}
712}
713
714impl From<crate::traits::LookupError> for DispatchError {
715	fn from(_: crate::traits::LookupError) -> Self {
716		Self::CannotLookup
717	}
718}
719
720impl From<crate::traits::BadOrigin> for DispatchError {
721	fn from(_: crate::traits::BadOrigin) -> Self {
722		Self::BadOrigin
723	}
724}
725
726/// Description of what went wrong when trying to complete an operation on a token.
727#[derive(
728	Eq,
729	PartialEq,
730	Clone,
731	Copy,
732	Encode,
733	Decode,
734	DecodeWithMemTracking,
735	Debug,
736	TypeInfo,
737	MaxEncodedLen,
738)]
739#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
740pub enum TokenError {
741	/// Funds are unavailable.
742	FundsUnavailable,
743	/// Some part of the balance gives the only provider reference to the account and thus cannot
744	/// be (re)moved.
745	OnlyProvider,
746	/// Account cannot exist with the funds that would be given.
747	BelowMinimum,
748	/// Account cannot be created.
749	CannotCreate,
750	/// The asset in question is unknown.
751	UnknownAsset,
752	/// Funds exist but are frozen.
753	Frozen,
754	/// Operation is not supported by the asset.
755	Unsupported,
756	/// Account cannot be created for a held balance.
757	CannotCreateHold,
758	/// Withdrawal would cause unwanted loss of account.
759	NotExpendable,
760	/// Account cannot receive the assets.
761	Blocked,
762}
763
764impl From<TokenError> for &'static str {
765	fn from(e: TokenError) -> &'static str {
766		match e {
767			TokenError::FundsUnavailable => "Funds are unavailable",
768			TokenError::OnlyProvider => "Account that must exist would die",
769			TokenError::BelowMinimum => "Account cannot exist with the funds that would be given",
770			TokenError::CannotCreate => "Account cannot be created",
771			TokenError::UnknownAsset => "The asset in question is unknown",
772			TokenError::Frozen => "Funds exist but are frozen",
773			TokenError::Unsupported => "Operation is not supported by the asset",
774			TokenError::CannotCreateHold => {
775				"Account cannot be created for recording amount on hold"
776			},
777			TokenError::NotExpendable => "Account that is desired to remain would die",
778			TokenError::Blocked => "Account cannot receive the assets",
779		}
780	}
781}
782
783impl From<TokenError> for DispatchError {
784	fn from(e: TokenError) -> DispatchError {
785		Self::Token(e)
786	}
787}
788
789impl From<ArithmeticError> for DispatchError {
790	fn from(e: ArithmeticError) -> DispatchError {
791		Self::Arithmetic(e)
792	}
793}
794
795impl From<TrieError> for DispatchError {
796	fn from(e: TrieError) -> DispatchError {
797		Self::Trie(e)
798	}
799}
800
801impl From<&'static str> for DispatchError {
802	fn from(err: &'static str) -> DispatchError {
803		Self::Other(err)
804	}
805}
806
807impl From<DispatchError> for &'static str {
808	fn from(err: DispatchError) -> &'static str {
809		use DispatchError::*;
810		match err {
811			Other(msg) => msg,
812			CannotLookup => "Cannot lookup",
813			BadOrigin => "Bad origin",
814			Module(ModuleError { message, .. }) => message.unwrap_or("Unknown module error"),
815			ConsumerRemaining => "Consumer remaining",
816			NoProviders => "No providers",
817			TooManyConsumers => "Too many consumers",
818			Token(e) => e.into(),
819			Arithmetic(e) => e.into(),
820			Transactional(e) => e.into(),
821			Exhausted => "Resources exhausted",
822			Corruption => "State corrupt",
823			Unavailable => "Resource unavailable",
824			RootNotAllowed => "Root not allowed",
825			Trie(e) => e.into(),
826		}
827	}
828}
829
830impl<T> From<DispatchErrorWithPostInfo<T>> for &'static str
831where
832	T: Eq + PartialEq + Clone + Copy + Encode + Decode + traits::Printable,
833{
834	fn from(err: DispatchErrorWithPostInfo<T>) -> &'static str {
835		err.error.into()
836	}
837}
838
839impl traits::Printable for DispatchError {
840	fn print(&self) {
841		use DispatchError::*;
842		"DispatchError".print();
843		match self {
844			Other(err) => err.print(),
845			CannotLookup => "Cannot lookup".print(),
846			BadOrigin => "Bad origin".print(),
847			Module(ModuleError { index, error, message }) => {
848				index.print();
849				error.print();
850				if let Some(msg) = message {
851					msg.print();
852				}
853			},
854			ConsumerRemaining => "Consumer remaining".print(),
855			NoProviders => "No providers".print(),
856			TooManyConsumers => "Too many consumers".print(),
857			Token(e) => {
858				"Token error: ".print();
859				<&'static str>::from(*e).print();
860			},
861			Arithmetic(e) => {
862				"Arithmetic error: ".print();
863				<&'static str>::from(*e).print();
864			},
865			Transactional(e) => {
866				"Transactional error: ".print();
867				<&'static str>::from(*e).print();
868			},
869			Exhausted => "Resources exhausted".print(),
870			Corruption => "State corrupt".print(),
871			Unavailable => "Resource unavailable".print(),
872			RootNotAllowed => "Root not allowed".print(),
873			Trie(e) => {
874				"Trie error: ".print();
875				<&'static str>::from(*e).print();
876			},
877		}
878	}
879}
880
881impl<T> traits::Printable for DispatchErrorWithPostInfo<T>
882where
883	T: Eq + PartialEq + Clone + Copy + Encode + Decode + traits::Printable,
884{
885	fn print(&self) {
886		self.error.print();
887		"PostInfo: ".print();
888		self.post_info.print();
889	}
890}
891
892/// This type specifies the outcome of dispatching a call to a module.
893///
894/// In case of failure an error specific to the module is returned.
895///
896/// Failure of the module call dispatching doesn't invalidate the extrinsic and it is still included
897/// in the block, therefore all state changes performed by the dispatched call are still persisted.
898///
899/// For example, if the dispatching of an extrinsic involves inclusion fee payment then these
900/// changes are going to be preserved even if the call dispatched failed.
901pub type DispatchOutcome = Result<(), DispatchError>;
902
903/// The result of applying of an extrinsic.
904///
905/// This type is typically used in the context of `BlockBuilder` to signal that the extrinsic
906/// in question cannot be included.
907///
908/// A block containing extrinsics that have a negative inclusion outcome is invalid. A negative
909/// result can only occur during the block production, where such extrinsics are detected and
910/// removed from the block that is being created and the transaction pool.
911///
912/// To rehash: every extrinsic in a valid block must return a positive `ApplyExtrinsicResult`.
913///
914/// Examples of reasons preventing inclusion in a block:
915/// - More block weight is required to process the extrinsic than is left in the block being built.
916///   This doesn't necessarily mean that the extrinsic is invalid, since it can still be included in
917///   the next block if it has enough spare weight available.
918/// - The sender doesn't have enough funds to pay the transaction inclusion fee. Including such a
919///   transaction in the block doesn't make sense.
920/// - The extrinsic supplied a bad signature. This transaction won't become valid ever.
921pub type ApplyExtrinsicResult =
922	Result<DispatchOutcome, transaction_validity::TransactionValidityError>;
923
924/// Same as `ApplyExtrinsicResult` but augmented with `PostDispatchInfo` on success.
925pub type ApplyExtrinsicResultWithInfo<T> =
926	Result<DispatchResultWithInfo<T>, transaction_validity::TransactionValidityError>;
927
928/// The error type used as return type in try runtime hooks.
929pub type TryRuntimeError = DispatchError;
930
931/// Verify a signature on an encoded value in a lazy manner. This can be
932/// an optimization if the signature scheme has an "unsigned" escape hash.
933pub fn verify_encoded_lazy<V: Verify, T: codec::Encode>(
934	sig: &V,
935	item: &T,
936	signer: &<V::Signer as IdentifyAccount>::AccountId,
937) -> bool {
938	// The `Lazy<T>` trait expresses something like `X: FnMut<Output = for<'a> &'a T>`.
939	// unfortunately this is a lifetime relationship that can't
940	// be expressed without generic associated types, better unification of HRTBs in type position,
941	// and some kind of integration into the Fn* traits.
942	struct LazyEncode<F> {
943		inner: F,
944		encoded: Option<Vec<u8>>,
945	}
946
947	impl<F: Fn() -> Vec<u8>> traits::Lazy<[u8]> for LazyEncode<F> {
948		fn get(&mut self) -> &[u8] {
949			self.encoded.get_or_insert_with(&self.inner).as_slice()
950		}
951	}
952
953	sig.verify(LazyEncode { inner: || item.encode(), encoded: None }, signer)
954}
955
956/// Checks that `$x` is equal to `$y` with an error rate of `$error`.
957///
958/// # Example
959///
960/// ```rust
961/// # fn main() {
962/// pezsp_runtime::assert_eq_error_rate!(10, 10, 0);
963/// pezsp_runtime::assert_eq_error_rate!(10, 11, 1);
964/// pezsp_runtime::assert_eq_error_rate!(12, 10, 2);
965/// # }
966/// ```
967///
968/// ```rust,should_panic
969/// # fn main() {
970/// pezsp_runtime::assert_eq_error_rate!(12, 10, 1);
971/// # }
972/// ```
973#[macro_export]
974#[cfg(feature = "std")]
975macro_rules! assert_eq_error_rate {
976	($x:expr, $y:expr, $error:expr $(,)?) => {
977		assert!(
978			($x >= $crate::Saturating::saturating_sub($y, $error))
979				&& ($x <= $crate::Saturating::saturating_add($y, $error)),
980			"{:?} != {:?} (with error rate {:?})",
981			$x,
982			$y,
983			$error,
984		);
985	};
986}
987
988/// Same as [`assert_eq_error_rate`], but intended to be used with floating point number, or
989/// generally those who do not have over/underflow potentials.
990#[macro_export]
991#[cfg(feature = "std")]
992macro_rules! assert_eq_error_rate_float {
993	($x:expr, $y:expr, $error:expr $(,)?) => {
994		assert!(
995			($x >= $y - $error) && ($x <= $y + $error),
996			"{:?} != {:?} (with error rate {:?})",
997			$x,
998			$y,
999			$error,
1000		);
1001	};
1002}
1003
1004/// Simple blob to hold an extrinsic without committing to its format and ensure it is serialized
1005/// correctly.
1006#[derive(PartialEq, Eq, Clone, Default, Encode, Decode, DecodeWithMemTracking)]
1007pub struct OpaqueExtrinsic(bytes::Bytes);
1008
1009impl TypeInfo for OpaqueExtrinsic {
1010	type Identity = Self;
1011	fn type_info() -> scale_info::Type {
1012		scale_info::Type::builder()
1013			.path(scale_info::Path::new("OpaqueExtrinsic", module_path!()))
1014			.composite(
1015				scale_info::build::Fields::unnamed()
1016					.field(|f| f.ty::<Vec<u8>>().type_name("Vec<u8>")),
1017			)
1018	}
1019}
1020
1021impl OpaqueExtrinsic {
1022	/// Convert an encoded extrinsic to an `OpaqueExtrinsic`.
1023	pub fn try_from_encoded_extrinsic(mut bytes: &[u8]) -> Result<Self, codec::Error> {
1024		Self::decode(&mut bytes)
1025	}
1026
1027	/// Convert an encoded extrinsic to an `OpaqueExtrinsic`.
1028	#[deprecated = "Use `try_from_encoded_extrinsic()` instead"]
1029	pub fn from_bytes(bytes: &[u8]) -> Result<Self, codec::Error> {
1030		Self::try_from_encoded_extrinsic(bytes)
1031	}
1032
1033	/// Create a new instance of `OpaqueExtrinsic` from a `Vec<u8>`.
1034	pub fn from_blob(bytes: Vec<u8>) -> Self {
1035		Self(bytes.into())
1036	}
1037
1038	/// Get the actual blob.
1039	pub fn inner(&self) -> &[u8] {
1040		&self.0
1041	}
1042}
1043
1044impl LazyExtrinsic for OpaqueExtrinsic {
1045	fn decode_unprefixed(data: &[u8]) -> Result<Self, codec::Error> {
1046		Ok(Self(data.to_vec().into()))
1047	}
1048}
1049
1050impl core::fmt::Debug for OpaqueExtrinsic {
1051	#[cfg(feature = "std")]
1052	fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
1053		write!(fmt, "{}", pezsp_core::hexdisplay::HexDisplay::from(&self.0.as_ref()))
1054	}
1055
1056	#[cfg(not(feature = "std"))]
1057	fn fmt(&self, _fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
1058		Ok(())
1059	}
1060}
1061
1062#[cfg(feature = "serde")]
1063impl ::serde::Serialize for OpaqueExtrinsic {
1064	fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error>
1065	where
1066		S: ::serde::Serializer,
1067	{
1068		codec::Encode::using_encoded(&self.0, |bytes| ::pezsp_core::bytes::serialize(bytes, seq))
1069	}
1070}
1071
1072#[cfg(feature = "serde")]
1073impl<'a> ::serde::Deserialize<'a> for OpaqueExtrinsic {
1074	fn deserialize<D>(de: D) -> Result<Self, D::Error>
1075	where
1076		D: ::serde::Deserializer<'a>,
1077	{
1078		let r = ::pezsp_core::bytes::deserialize(de)?;
1079		Decode::decode(&mut &r[..])
1080			.map_err(|e| ::serde::de::Error::custom(alloc::format!("Decode error: {}", e)))
1081	}
1082}
1083
1084impl traits::ExtrinsicLike for OpaqueExtrinsic {
1085	fn is_bare(&self) -> bool {
1086		false
1087	}
1088}
1089
1090/// Print something that implements `Printable` from the runtime.
1091pub fn print(print: impl traits::Printable) {
1092	print.print();
1093}
1094
1095/// Utility function to declare string literals backed by an array of length N.
1096///
1097/// The input can be shorter than N, in that case the end of the array is padded with zeros.
1098///
1099/// [`str_array`] is useful when converting strings that end up in the storage as fixed size arrays
1100/// or in const contexts where static data types have strings that could also end up in the storage.
1101///
1102/// # Example
1103///
1104/// ```rust
1105/// # use pezsp_runtime::str_array;
1106/// const MY_STR: [u8; 6] = str_array("data");
1107/// assert_eq!(MY_STR, *b"data\0\0");
1108/// ```
1109pub const fn str_array<const N: usize>(s: &str) -> [u8; N] {
1110	debug_assert!(s.len() <= N, "String literal doesn't fit in array");
1111	let mut i = 0;
1112	let mut arr = [0; N];
1113	let s = s.as_bytes();
1114	while i < s.len() {
1115		arr[i] = s[i];
1116		i += 1;
1117	}
1118	arr
1119}
1120
1121/// Describes on what should happen with a storage transaction.
1122pub enum TransactionOutcome<R> {
1123	/// Commit the transaction.
1124	Commit(R),
1125	/// Rollback the transaction.
1126	Rollback(R),
1127}
1128
1129impl<R> TransactionOutcome<R> {
1130	/// Convert into the inner type.
1131	pub fn into_inner(self) -> R {
1132		match self {
1133			Self::Commit(r) => r,
1134			Self::Rollback(r) => r,
1135		}
1136	}
1137}
1138
1139/// Confines the kind of extrinsics that can be included in a block.
1140#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, Encode, Decode, TypeInfo)]
1141pub enum ExtrinsicInclusionMode {
1142	/// All extrinsics are allowed to be included in this block.
1143	#[default]
1144	AllExtrinsics,
1145	/// Inherents are allowed to be included.
1146	OnlyInherents,
1147}
1148
1149/// Simple blob that hold a value in an encoded form without committing to its type.
1150#[derive(Decode, Encode, PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)]
1151pub struct OpaqueValue(Vec<u8>);
1152impl OpaqueValue {
1153	/// Create a new `OpaqueValue` using the given encoded representation.
1154	pub fn new(inner: Vec<u8>) -> OpaqueValue {
1155		OpaqueValue(inner)
1156	}
1157
1158	/// Try to decode this `OpaqueValue` into the given concrete type.
1159	pub fn decode<T: Decode>(&self) -> Option<T> {
1160		Decode::decode(&mut &self.0[..]).ok()
1161	}
1162}
1163
1164// TODO: Remove in future versions and clean up `parse_str_literal` in `sp-version-proc-macro`
1165/// Deprecated `Cow::Borrowed()` wrapper.
1166#[macro_export]
1167#[deprecated = "Use Cow::Borrowed() instead of create_runtime_str!()"]
1168macro_rules! create_runtime_str {
1169	( $y:expr ) => {{
1170		$crate::Cow::Borrowed($y)
1171	}};
1172}
1173// TODO: Re-export for ^ macro `create_runtime_str`, should be removed once macro is gone
1174#[doc(hidden)]
1175pub use alloc::borrow::Cow;
1176
1177// TODO: Remove in future versions
1178/// Deprecated alias to improve upgrade experience
1179#[deprecated = "Use String or Cow<'static, str> instead"]
1180pub type RuntimeString = alloc::string::String;
1181
1182#[cfg(test)]
1183mod tests {
1184	use crate::traits::BlakeTwo256;
1185
1186	use super::*;
1187	use codec::{Decode, Encode};
1188	use pezsp_core::{crypto::Pair, hex2array};
1189	use pezsp_io::TestExternalities;
1190	use pezsp_state_machine::create_proof_check_backend;
1191
1192	#[test]
1193	fn opaque_extrinsic_serialization() {
1194		let ex = OpaqueExtrinsic::from_blob(vec![1, 2, 3, 4]);
1195		assert_eq!(serde_json::to_string(&ex).unwrap(), "\"0x1001020304\"".to_owned());
1196	}
1197
1198	#[test]
1199	fn dispatch_error_encoding() {
1200		let error = DispatchError::Module(ModuleError {
1201			index: 1,
1202			error: [2, 0, 0, 0],
1203			message: Some("error message"),
1204		});
1205		let encoded = error.encode();
1206		let decoded = DispatchError::decode(&mut &encoded[..]).unwrap();
1207		assert_eq!(encoded, vec![3, 1, 2, 0, 0, 0]);
1208		assert_eq!(
1209			decoded,
1210			DispatchError::Module(ModuleError { index: 1, error: [2, 0, 0, 0], message: None })
1211		);
1212	}
1213
1214	#[test]
1215	fn dispatch_error_equality() {
1216		use DispatchError::*;
1217
1218		let variants = vec![
1219			Other("foo"),
1220			Other("bar"),
1221			CannotLookup,
1222			BadOrigin,
1223			Module(ModuleError { index: 1, error: [1, 0, 0, 0], message: None }),
1224			Module(ModuleError { index: 1, error: [2, 0, 0, 0], message: None }),
1225			Module(ModuleError { index: 2, error: [1, 0, 0, 0], message: None }),
1226			ConsumerRemaining,
1227			NoProviders,
1228			Token(TokenError::FundsUnavailable),
1229			Token(TokenError::OnlyProvider),
1230			Token(TokenError::BelowMinimum),
1231			Token(TokenError::CannotCreate),
1232			Token(TokenError::UnknownAsset),
1233			Token(TokenError::Frozen),
1234			Arithmetic(ArithmeticError::Overflow),
1235			Arithmetic(ArithmeticError::Underflow),
1236			Arithmetic(ArithmeticError::DivisionByZero),
1237		];
1238		for (i, variant) in variants.iter().enumerate() {
1239			for (j, other_variant) in variants.iter().enumerate() {
1240				if i == j {
1241					assert_eq!(variant, other_variant);
1242				} else {
1243					assert_ne!(variant, other_variant);
1244				}
1245			}
1246		}
1247
1248		// Ignores `message` field in `Module` variant.
1249		assert_eq!(
1250			Module(ModuleError { index: 1, error: [1, 0, 0, 0], message: Some("foo") }),
1251			Module(ModuleError { index: 1, error: [1, 0, 0, 0], message: None }),
1252		);
1253	}
1254
1255	#[test]
1256	fn multi_signature_ecdsa_verify_works() {
1257		let msg = &b"test-message"[..];
1258		let (pair, _) = ecdsa::Pair::generate();
1259
1260		let signature = pair.sign(&msg);
1261		assert!(ecdsa::Pair::verify(&signature, msg, &pair.public()));
1262
1263		let multi_sig = MultiSignature::from(signature);
1264		let multi_signer = MultiSigner::from(pair.public());
1265		assert!(multi_sig.verify(msg, &multi_signer.into_account()));
1266	}
1267
1268	#[test]
1269	fn multi_signature_eth_verify_works() {
1270		let msg = &b"test-message"[..];
1271		let (pair, _) = ecdsa::KeccakPair::generate();
1272
1273		let signature = pair.sign(&msg);
1274		assert!(ecdsa::KeccakPair::verify(&signature, msg, &pair.public()));
1275
1276		let multi_sig = MultiSignature::Eth(signature);
1277		let multi_signer = MultiSigner::Eth(pair.public());
1278		assert!(multi_sig.verify(msg, &multi_signer.into_account()));
1279	}
1280
1281	#[test]
1282	fn multi_signer_eth_address_works() {
1283		let ecdsa_pair = ecdsa::Pair::from_seed(&[0x42; 32]);
1284		let eth_pair = ecdsa::KeccakPair::from_seed(&[0x42; 32]);
1285		let ecdsa = MultiSigner::Ecdsa(ecdsa_pair.public()).into_account();
1286		let eth = MultiSigner::Eth(eth_pair.public()).into_account();
1287
1288		assert_eq!(&<AccountId32 as AsRef<[u8; 32]>>::as_ref(&eth)[20..], &[0xEE; 12]);
1289		assert_eq!(
1290			ecdsa,
1291			hex2array!("ff241710529476ac87c67b66ccdc42f95a14b49a896164839fe675dc6f579614").into(),
1292		);
1293		assert_eq!(
1294			eth,
1295			hex2array!("2714c48edc39bc2714729e6530760d62344d6698eeeeeeeeeeeeeeeeeeeeeeee").into(),
1296		);
1297	}
1298
1299	#[test]
1300	fn execute_and_generate_proof_works() {
1301		use codec::Encode;
1302		use pezsp_state_machine::Backend;
1303		let mut ext = TestExternalities::default();
1304
1305		ext.insert(b"a".to_vec(), vec![1u8; 33]);
1306		ext.insert(b"b".to_vec(), vec![2u8; 33]);
1307		ext.insert(b"c".to_vec(), vec![3u8; 33]);
1308		ext.insert(b"d".to_vec(), vec![4u8; 33]);
1309
1310		let pre_root = *ext.backend.root();
1311		let (_, proof) = ext.execute_and_prove(|| {
1312			pezsp_io::storage::get(b"a");
1313			pezsp_io::storage::get(b"b");
1314			pezsp_io::storage::get(b"v");
1315			pezsp_io::storage::get(b"d");
1316		});
1317
1318		let compact_proof = proof.clone().into_compact_proof::<BlakeTwo256>(pre_root).unwrap();
1319		let compressed_proof = zstd::stream::encode_all(&compact_proof.encode()[..], 0).unwrap();
1320
1321		// just an example of how you'd inspect the size of the proof.
1322		println!("proof size: {:?}", proof.encoded_size());
1323		println!("compact proof size: {:?}", compact_proof.encoded_size());
1324		println!("zstd-compressed compact proof size: {:?}", &compressed_proof.len());
1325
1326		// create a new trie-backed from the proof and make sure it contains everything
1327		let proof_check = create_proof_check_backend::<BlakeTwo256>(pre_root, proof).unwrap();
1328		assert_eq!(proof_check.storage(b"a",).unwrap().unwrap(), vec![1u8; 33]);
1329
1330		let _ = ext.execute_and_prove(|| {
1331			pezsp_io::storage::set(b"a", &vec![1u8; 44]);
1332		});
1333
1334		// ensure that these changes are propagated to the backend.
1335
1336		ext.execute_with(|| {
1337			assert_eq!(pezsp_io::storage::get(b"a").unwrap(), vec![1u8; 44]);
1338			assert_eq!(pezsp_io::storage::get(b"b").unwrap(), vec![2u8; 33]);
1339		});
1340	}
1341}
1342
1343// NOTE: we have to test the pezsp_core stuff also from a different crate to check that the macro
1344// can access the pezsp_core crate.
1345#[cfg(test)]
1346mod pezsp_core_tests {
1347	use super::*;
1348
1349	pezsp_core::generate_feature_enabled_macro!(if_test, test, $);
1350	pezsp_core::generate_feature_enabled_macro!(if_not_test, not(test), $);
1351
1352	#[test]
1353	#[should_panic]
1354	fn generate_feature_enabled_macro_panics() {
1355		if_test!(panic!("This should panic"));
1356	}
1357
1358	#[test]
1359	fn generate_feature_enabled_macro_works() {
1360		if_not_test!(panic!("This should not panic"));
1361	}
1362}