tp_runtime/
lib.rs

1// This file is part of Tetcore.
2
3// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.
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//! Runtime Modules shared primitive types.
19
20#![warn(missing_docs)]
21#![cfg_attr(not(feature = "std"), no_std)]
22
23// to allow benchmarking
24#![cfg_attr(feature = "bench", feature(test))]
25#[cfg(feature = "bench")] extern crate test;
26
27#[doc(hidden)]
28pub use codec;
29#[cfg(feature = "std")]
30#[doc(hidden)]
31pub use serde;
32#[doc(hidden)]
33pub use tetcore_std;
34
35#[doc(hidden)]
36pub use paste;
37
38#[doc(hidden)]
39pub use tet_application_crypto as app_crypto;
40
41#[cfg(feature = "std")]
42pub use tet_core::storage::{Storage, StorageChild};
43
44use tetcore_std::prelude::*;
45use tetcore_std::convert::TryFrom;
46use tet_core::{crypto::{self, Public}, ed25519, sr25519, ecdsa, hash::{H256, H512}};
47
48use codec::{Encode, Decode};
49
50pub mod curve;
51pub mod generic;
52pub mod offchain;
53#[cfg(feature = "std")]
54pub mod testing;
55pub mod traits;
56pub mod transaction_validity;
57pub mod random_number_generator;
58mod runtime_string;
59mod multiaddress;
60
61pub use crate::runtime_string::*;
62
63// Re-export Multiaddress
64pub use multiaddress::MultiAddress;
65
66/// Re-export these since they're only "kind of" generic.
67pub use generic::{DigestItem, Digest};
68
69/// Re-export this since it's part of the API of this crate.
70pub use tet_core::{TypeId, crypto::{key_types, KeyTypeId, CryptoType, CryptoTypeId, AccountId32}};
71pub use tet_application_crypto::{RuntimeAppPublic, BoundToRuntimeAppPublic};
72
73/// Re-export `RuntimeDebug`, to avoid dependency clutter.
74pub use tet_core::RuntimeDebug;
75
76/// Re-export top-level arithmetic stuff.
77pub use arithmetic::{
78	PerThing, Perquintill, Perbill, Permill, Percent, PerU16, InnerOf, UpperOf,
79	Rational128, FixedI64, FixedI128, FixedU128, FixedPointNumber, FixedPointOperand,
80	traits::SaturatedConversion,
81};
82/// Re-export 128 bit helpers.
83pub use arithmetic::helpers_128bit;
84/// Re-export big_uint stuff.
85pub use arithmetic::biguint;
86
87pub use random_number_generator::RandomNumberGenerator;
88
89pub use either::Either;
90
91/// An abstraction over justification for a block's validity under a consensus algorithm.
92///
93/// Essentially a finality proof. The exact formulation will vary between consensus
94/// algorithms. In the case where there are multiple valid proofs, inclusion within
95/// the block itself would allow swapping justifications to change the block's hash
96/// (and thus fork the chain). Sending a `Justification` alongside a block instead
97/// bypasses this problem.
98pub type Justification = Vec<u8>;
99
100use traits::{Verify, Lazy};
101
102/// A module identifier. These are per module and should be stored in a registry somewhere.
103#[derive(Clone, Copy, Eq, PartialEq, Encode, Decode)]
104pub struct ModuleId(pub [u8; 8]);
105
106impl TypeId for ModuleId {
107	const TYPE_ID: [u8; 4] = *b"modl";
108}
109
110#[cfg(feature = "std")]
111pub use serde::{Serialize, Deserialize, de::DeserializeOwned};
112use crate::traits::IdentifyAccount;
113
114/// Complex storage builder stuff.
115#[cfg(feature = "std")]
116pub trait BuildStorage {
117	/// Build the storage out of this builder.
118	fn build_storage(&self) -> Result<tet_core::storage::Storage, String> {
119		let mut storage = Default::default();
120		self.assimilate_storage(&mut storage)?;
121		Ok(storage)
122	}
123	/// Assimilate the storage for this module into pre-existing overlays.
124	fn assimilate_storage(
125		&self,
126		storage: &mut tet_core::storage::Storage,
127	) -> Result<(), String>;
128}
129
130/// Something that can build the genesis storage of a module.
131#[cfg(feature = "std")]
132pub trait BuildModuleGenesisStorage<T, I>: Sized {
133	/// Create the module genesis storage into the given `storage` and `child_storage`.
134	fn build_module_genesis_storage(
135		&self,
136		storage: &mut tet_core::storage::Storage,
137	) -> Result<(), String>;
138}
139
140#[cfg(feature = "std")]
141impl BuildStorage for tet_core::storage::Storage {
142	fn assimilate_storage(
143		&self,
144		storage: &mut tet_core::storage::Storage,
145	)-> Result<(), String> {
146		storage.top.extend(self.top.iter().map(|(k, v)| (k.clone(), v.clone())));
147		for (k, other_map) in self.children_default.iter() {
148			let k = k.clone();
149			if let Some(map) = storage.children_default.get_mut(&k) {
150				map.data.extend(other_map.data.iter().map(|(k, v)| (k.clone(), v.clone())));
151				if !map.child_info.try_update(&other_map.child_info) {
152					return Err("Incompatible child info update".to_string());
153				}
154			} else {
155				storage.children_default.insert(k, other_map.clone());
156			}
157		}
158		Ok(())
159	}
160}
161
162#[cfg(feature = "std")]
163impl BuildStorage for () {
164	fn assimilate_storage(
165		&self,
166		_: &mut tet_core::storage::Storage,
167	) -> Result<(), String> {
168		Err("`assimilate_storage` not implemented for `()`".into())
169	}
170}
171
172/// Consensus engine unique ID.
173pub type ConsensusEngineId = [u8; 4];
174
175/// Signature verify that can work with any known signature types..
176#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
177#[derive(Eq, PartialEq, Clone, Encode, Decode, RuntimeDebug)]
178pub enum MultiSignature {
179	/// An Ed25519 signature.
180	Ed25519(ed25519::Signature),
181	/// An Sr25519 signature.
182	Sr25519(sr25519::Signature),
183	/// An ECDSA/SECP256k1 signature.
184	Ecdsa(ecdsa::Signature),
185}
186
187impl From<ed25519::Signature> for MultiSignature {
188	fn from(x: ed25519::Signature) -> Self {
189		MultiSignature::Ed25519(x)
190	}
191}
192
193impl TryFrom<MultiSignature> for ed25519::Signature {
194	type Error = ();
195	fn try_from(m: MultiSignature) -> Result<Self, Self::Error> {
196		if let MultiSignature::Ed25519(x) = m { Ok(x) } else { Err(()) }
197	}
198}
199
200impl From<sr25519::Signature> for MultiSignature {
201	fn from(x: sr25519::Signature) -> Self {
202		MultiSignature::Sr25519(x)
203	}
204}
205
206impl TryFrom<MultiSignature> for sr25519::Signature {
207	type Error = ();
208	fn try_from(m: MultiSignature) -> Result<Self, Self::Error> {
209		if let MultiSignature::Sr25519(x) = m { Ok(x) } else { Err(()) }
210	}
211}
212
213impl From<ecdsa::Signature> for MultiSignature {
214	fn from(x: ecdsa::Signature) -> Self {
215		MultiSignature::Ecdsa(x)
216	}
217}
218
219impl TryFrom<MultiSignature> for ecdsa::Signature {
220	type Error = ();
221	fn try_from(m: MultiSignature) -> Result<Self, Self::Error> {
222		if let MultiSignature::Ecdsa(x) = m { Ok(x) } else { Err(()) }
223	}
224}
225
226impl Default for MultiSignature {
227	fn default() -> Self {
228		MultiSignature::Ed25519(Default::default())
229	}
230}
231
232/// Public key for any known crypto algorithm.
233#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Encode, Decode, RuntimeDebug)]
234#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
235pub enum MultiSigner {
236	/// An Ed25519 identity.
237	Ed25519(ed25519::Public),
238	/// An Sr25519 identity.
239	Sr25519(sr25519::Public),
240	/// An SECP256k1/ECDSA identity (actually, the Blake2 hash of the compressed pub key).
241	Ecdsa(ecdsa::Public),
242}
243
244impl Default for MultiSigner {
245	fn default() -> Self {
246		MultiSigner::Ed25519(Default::default())
247	}
248}
249
250/// NOTE: This implementations is required by `SimpleAddressDeterminer`,
251/// we convert the hash into some AccountId, it's fine to use any scheme.
252impl<T: Into<H256>> crypto::UncheckedFrom<T> for MultiSigner {
253	fn unchecked_from(x: T) -> Self {
254		ed25519::Public::unchecked_from(x.into()).into()
255	}
256}
257
258impl AsRef<[u8]> for MultiSigner {
259	fn as_ref(&self) -> &[u8] {
260		match *self {
261			MultiSigner::Ed25519(ref who) => who.as_ref(),
262			MultiSigner::Sr25519(ref who) => who.as_ref(),
263			MultiSigner::Ecdsa(ref who) => who.as_ref(),
264		}
265	}
266}
267
268impl traits::IdentifyAccount for MultiSigner {
269	type AccountId = AccountId32;
270	fn into_account(self) -> AccountId32 {
271		match self {
272			MultiSigner::Ed25519(who) => <[u8; 32]>::from(who).into(),
273			MultiSigner::Sr25519(who) => <[u8; 32]>::from(who).into(),
274			MultiSigner::Ecdsa(who) => tet_io::hashing::blake2_256(&who.as_ref()[..]).into(),
275		}
276	}
277}
278
279impl From<ed25519::Public> for MultiSigner {
280	fn from(x: ed25519::Public) -> Self {
281		MultiSigner::Ed25519(x)
282	}
283}
284
285impl TryFrom<MultiSigner> for ed25519::Public {
286	type Error = ();
287	fn try_from(m: MultiSigner) -> Result<Self, Self::Error> {
288		if let MultiSigner::Ed25519(x) = m { Ok(x) } else { Err(()) }
289	}
290}
291
292impl From<sr25519::Public> for MultiSigner {
293	fn from(x: sr25519::Public) -> Self {
294		MultiSigner::Sr25519(x)
295	}
296}
297
298impl TryFrom<MultiSigner> for sr25519::Public {
299	type Error = ();
300	fn try_from(m: MultiSigner) -> Result<Self, Self::Error> {
301		if let MultiSigner::Sr25519(x) = m { Ok(x) } else { Err(()) }
302	}
303}
304
305impl From<ecdsa::Public> for MultiSigner {
306	fn from(x: ecdsa::Public) -> Self {
307		MultiSigner::Ecdsa(x)
308	}
309}
310
311impl TryFrom<MultiSigner> for ecdsa::Public {
312	type Error = ();
313	fn try_from(m: MultiSigner) -> Result<Self, Self::Error> {
314		if let MultiSigner::Ecdsa(x) = m { Ok(x) } else { Err(()) }
315	}
316}
317
318#[cfg(feature = "std")]
319impl std::fmt::Display for MultiSigner {
320	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
321		match *self {
322			MultiSigner::Ed25519(ref who) => write!(fmt, "ed25519: {}", who),
323			MultiSigner::Sr25519(ref who) => write!(fmt, "sr25519: {}", who),
324			MultiSigner::Ecdsa(ref who) => write!(fmt, "ecdsa: {}", who),
325		}
326	}
327}
328
329impl Verify for MultiSignature {
330	type Signer = MultiSigner;
331	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &AccountId32) -> bool {
332		match (self, signer) {
333			(MultiSignature::Ed25519(ref sig), who) => sig.verify(msg, &ed25519::Public::from_slice(who.as_ref())),
334			(MultiSignature::Sr25519(ref sig), who) => sig.verify(msg, &sr25519::Public::from_slice(who.as_ref())),
335			(MultiSignature::Ecdsa(ref sig), who) => {
336				let m = tet_io::hashing::blake2_256(msg.get());
337				match tet_io::crypto::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m) {
338					Ok(pubkey) =>
339						&tet_io::hashing::blake2_256(pubkey.as_ref())
340							== <dyn AsRef<[u8; 32]>>::as_ref(who),
341					_ => false,
342				}
343			}
344		}
345	}
346}
347
348/// Signature verify that can work with any known signature types..
349#[derive(Eq, PartialEq, Clone, Default, Encode, Decode, RuntimeDebug)]
350#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
351pub struct AnySignature(H512);
352
353impl Verify for AnySignature {
354	type Signer = sr25519::Public;
355	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &sr25519::Public) -> bool {
356		let msg = msg.get();
357		sr25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
358			.map(|s| s.verify(msg, signer))
359			.unwrap_or(false)
360		|| ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
361			.map(|s| s.verify(msg, &ed25519::Public::from_slice(signer.as_ref())))
362			.unwrap_or(false)
363	}
364}
365
366impl From<sr25519::Signature> for AnySignature {
367	fn from(s: sr25519::Signature) -> Self {
368		AnySignature(s.into())
369	}
370}
371
372impl From<ed25519::Signature> for AnySignature {
373	fn from(s: ed25519::Signature) -> Self {
374		AnySignature(s.into())
375	}
376}
377
378impl From<DispatchError> for DispatchOutcome {
379	fn from(err: DispatchError) -> Self {
380		Err(err)
381	}
382}
383
384/// This is the legacy return type of `Dispatchable`. It is still exposed for compatibility reasons.
385/// The new return type is `DispatchResultWithInfo`. FABRIC runtimes should use
386/// `fabric_support::dispatch::DispatchResult`.
387pub type DispatchResult = tetcore_std::result::Result<(), DispatchError>;
388
389/// Return type of a `Dispatchable` which contains the `DispatchResult` and additional information
390/// about the `Dispatchable` that is only known post dispatch.
391pub type DispatchResultWithInfo<T> = tetcore_std::result::Result<T, DispatchErrorWithPostInfo<T>>;
392
393/// Reason why a dispatch call failed.
394#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, RuntimeDebug)]
395#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
396pub enum DispatchError {
397	/// Some error occurred.
398	Other(#[codec(skip)] #[cfg_attr(feature = "std", serde(skip_deserializing))] &'static str),
399	/// Failed to lookup some data.
400	CannotLookup,
401	/// A bad origin.
402	BadOrigin,
403	/// A custom error in a module.
404	Module {
405		/// Module index, matching the metadata module index.
406		index: u8,
407		/// Module specific error value.
408		error: u8,
409		/// Optional error message.
410		#[codec(skip)]
411		#[cfg_attr(feature = "std", serde(skip_deserializing))]
412		message: Option<&'static str>,
413	},
414	/// At least one consumer is remaining so the account cannot be destroyed.
415	ConsumerRemaining,
416	/// There are no providers so the account cannot be created.
417	NoProviders,
418}
419
420/// Result of a `Dispatchable` which contains the `DispatchResult` and additional information about
421/// the `Dispatchable` that is only known post dispatch.
422#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, RuntimeDebug)]
423pub struct DispatchErrorWithPostInfo<Info> where
424	Info: Eq + PartialEq + Clone + Copy + Encode + Decode + traits::Printable
425{
426	/// Additional information about the `Dispatchable` which is only known post dispatch.
427	pub post_info: Info,
428	/// The actual `DispatchResult` indicating whether the dispatch was successful.
429	pub error: DispatchError,
430}
431
432impl DispatchError {
433	/// Return the same error but without the attached message.
434	pub fn stripped(self) -> Self {
435		match self {
436			DispatchError::Module { index, error, message: Some(_) }
437				=> DispatchError::Module { index, error, message: None },
438			m => m,
439		}
440	}
441}
442
443impl<T, E> From<E> for DispatchErrorWithPostInfo<T> where
444	T: Eq + PartialEq + Clone + Copy + Encode + Decode + traits::Printable + Default,
445	E: Into<DispatchError>
446{
447	fn from(error: E) -> Self {
448		Self {
449			post_info: Default::default(),
450			error: error.into(),
451		}
452	}
453}
454
455impl From<crate::traits::LookupError> for DispatchError {
456	fn from(_: crate::traits::LookupError) -> Self {
457		Self::CannotLookup
458	}
459}
460
461impl From<crate::traits::BadOrigin> for DispatchError {
462	fn from(_: crate::traits::BadOrigin) -> Self {
463		Self::BadOrigin
464	}
465}
466
467impl From<crate::traits::StoredMapError> for DispatchError {
468	fn from(e: crate::traits::StoredMapError) -> Self {
469		match e {
470			crate::traits::StoredMapError::ConsumerRemaining => Self::ConsumerRemaining,
471			crate::traits::StoredMapError::NoProviders => Self::NoProviders,
472		}
473	}
474}
475
476impl From<&'static str> for DispatchError {
477	fn from(err: &'static str) -> DispatchError {
478		DispatchError::Other(err)
479	}
480}
481
482impl From<DispatchError> for &'static str {
483	fn from(err: DispatchError) -> &'static str {
484		match err {
485			DispatchError::Other(msg) => msg,
486			DispatchError::CannotLookup => "Cannot lookup",
487			DispatchError::BadOrigin => "Bad origin",
488			DispatchError::Module { message, .. } => message.unwrap_or("Unknown module error"),
489			DispatchError::ConsumerRemaining => "Consumer remaining",
490			DispatchError::NoProviders => "No providers",
491		}
492	}
493}
494
495impl<T> From<DispatchErrorWithPostInfo<T>> for &'static str where
496	T: Eq + PartialEq + Clone + Copy + Encode + Decode + traits::Printable
497{
498	fn from(err: DispatchErrorWithPostInfo<T>) -> &'static str {
499		err.error.into()
500	}
501}
502
503impl traits::Printable for DispatchError {
504	fn print(&self) {
505		"DispatchError".print();
506		match self {
507			Self::Other(err) => err.print(),
508			Self::CannotLookup => "Cannot lookup".print(),
509			Self::BadOrigin => "Bad origin".print(),
510			Self::Module { index, error, message } => {
511				index.print();
512				error.print();
513				if let Some(msg) = message {
514					msg.print();
515				}
516			}
517			Self::ConsumerRemaining => "Consumer remaining".print(),
518			Self::NoProviders => "No providers".print(),
519		}
520	}
521}
522
523impl<T> traits::Printable for DispatchErrorWithPostInfo<T> where
524	T: Eq + PartialEq + Clone + Copy + Encode + Decode + traits::Printable
525{
526	fn print(&self) {
527		self.error.print();
528		"PostInfo: ".print();
529		self.post_info.print();
530	}
531}
532
533/// This type specifies the outcome of dispatching a call to a module.
534///
535/// In case of failure an error specific to the module is returned.
536///
537/// Failure of the module call dispatching doesn't invalidate the extrinsic and it is still included
538/// in the block, therefore all state changes performed by the dispatched call are still persisted.
539///
540/// For example, if the dispatching of an extrinsic involves inclusion fee payment then these
541/// changes are going to be preserved even if the call dispatched failed.
542pub type DispatchOutcome = Result<(), DispatchError>;
543
544/// The result of applying of an extrinsic.
545///
546/// This type is typically used in the context of `BlockBuilder` to signal that the extrinsic
547/// in question cannot be included.
548///
549/// A block containing extrinsics that have a negative inclusion outcome is invalid. A negative
550/// result can only occur during the block production, where such extrinsics are detected and
551/// removed from the block that is being created and the transaction pool.
552///
553/// To rehash: every extrinsic in a valid block must return a positive `ApplyExtrinsicResult`.
554///
555/// Examples of reasons preventing inclusion in a block:
556/// - More block weight is required to process the extrinsic than is left in the block being built.
557///   This doesn't necessarily mean that the extrinsic is invalid, since it can still be
558///   included in the next block if it has enough spare weight available.
559/// - The sender doesn't have enough funds to pay the transaction inclusion fee. Including such
560///   a transaction in the block doesn't make sense.
561/// - The extrinsic supplied a bad signature. This transaction won't become valid ever.
562pub type ApplyExtrinsicResult = Result<DispatchOutcome, transaction_validity::TransactionValidityError>;
563
564/// Same as `ApplyExtrinsicResult` but augmented with `PostDispatchInfo` on success.
565pub type ApplyExtrinsicResultWithInfo<T> =
566	Result<DispatchResultWithInfo<T>, transaction_validity::TransactionValidityError>;
567
568/// Verify a signature on an encoded value in a lazy manner. This can be
569/// an optimization if the signature scheme has an "unsigned" escape hash.
570pub fn verify_encoded_lazy<V: Verify, T: codec::Encode>(
571	sig: &V,
572	item: &T,
573	signer: &<V::Signer as IdentifyAccount>::AccountId
574) -> bool {
575	// The `Lazy<T>` trait expresses something like `X: FnMut<Output = for<'a> &'a T>`.
576	// unfortunately this is a lifetime relationship that can't
577	// be expressed without generic associated types, better unification of HRTBs in type position,
578	// and some kind of integration into the Fn* traits.
579	struct LazyEncode<F> {
580		inner: F,
581		encoded: Option<Vec<u8>>,
582	}
583
584	impl<F: Fn() -> Vec<u8>> traits::Lazy<[u8]> for LazyEncode<F> {
585		fn get(&mut self) -> &[u8] {
586			self.encoded.get_or_insert_with(&self.inner).as_slice()
587		}
588	}
589
590	sig.verify(
591		LazyEncode { inner: || item.encode(), encoded: None },
592		signer,
593	)
594}
595
596/// Checks that `$x` is equal to `$y` with an error rate of `$error`.
597///
598/// # Example
599///
600/// ```rust
601/// # fn main() {
602/// tp_runtime::assert_eq_error_rate!(10, 10, 0);
603/// tp_runtime::assert_eq_error_rate!(10, 11, 1);
604/// tp_runtime::assert_eq_error_rate!(12, 10, 2);
605/// # }
606/// ```
607///
608/// ```rust,should_panic
609/// # fn main() {
610/// tp_runtime::assert_eq_error_rate!(12, 10, 1);
611/// # }
612/// ```
613#[macro_export]
614#[cfg(feature = "std")]
615macro_rules! assert_eq_error_rate {
616	($x:expr, $y:expr, $error:expr $(,)?) => {
617		assert!(
618			($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error)),
619			"{:?} != {:?} (with error rate {:?})",
620			$x,
621			$y,
622			$error,
623		);
624	};
625}
626
627/// Simple blob to hold an extrinsic without committing to its format and ensure it is serialized
628/// correctly.
629#[derive(PartialEq, Eq, Clone, Default, Encode, Decode)]
630pub struct OpaqueExtrinsic(Vec<u8>);
631
632impl OpaqueExtrinsic {
633	/// Convert an encoded extrinsic to an `OpaqueExtrinsic`.
634	pub fn from_bytes(mut bytes: &[u8]) -> Result<Self, codec::Error> {
635		OpaqueExtrinsic::decode(&mut bytes)
636	}
637}
638
639#[cfg(feature = "std")]
640impl tetsy_util_mem::MallocSizeOf for OpaqueExtrinsic {
641	fn size_of(&self, ops: &mut tetsy_util_mem::MallocSizeOfOps) -> usize {
642		self.0.size_of(ops)
643	}
644}
645
646impl tetcore_std::fmt::Debug for OpaqueExtrinsic {
647	#[cfg(feature = "std")]
648	fn fmt(&self, fmt: &mut tetcore_std::fmt::Formatter) -> tetcore_std::fmt::Result {
649		write!(fmt, "{}", tet_core::hexdisplay::HexDisplay::from(&self.0))
650	}
651
652	#[cfg(not(feature = "std"))]
653	fn fmt(&self, _fmt: &mut tetcore_std::fmt::Formatter) -> tetcore_std::fmt::Result {
654		Ok(())
655	}
656}
657
658
659#[cfg(feature = "std")]
660impl ::serde::Serialize for OpaqueExtrinsic {
661	fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
662		codec::Encode::using_encoded(&self.0, |bytes| ::tet_core::bytes::serialize(bytes, seq))
663	}
664}
665
666#[cfg(feature = "std")]
667impl<'a> ::serde::Deserialize<'a> for OpaqueExtrinsic {
668	fn deserialize<D>(de: D) -> Result<Self, D::Error> where D: ::serde::Deserializer<'a> {
669		let r = ::tet_core::bytes::deserialize(de)?;
670		Decode::decode(&mut &r[..])
671			.map_err(|e| ::serde::de::Error::custom(format!("Decode error: {}", e)))
672	}
673}
674
675impl traits::Extrinsic for OpaqueExtrinsic {
676	type Call = ();
677	type SignaturePayload = ();
678}
679
680/// Print something that implements `Printable` from the runtime.
681pub fn print(print: impl traits::Printable) {
682	print.print();
683}
684
685
686/// Batching session.
687///
688/// To be used in runtime only. Outside of runtime, just construct
689/// `BatchVerifier` directly.
690#[must_use = "`verify()` needs to be called to finish batch signature verification!"]
691pub struct SignatureBatching(bool);
692
693impl SignatureBatching {
694	/// Start new batching session.
695	pub fn start() -> Self {
696		tet_io::crypto::start_batch_verify();
697		SignatureBatching(false)
698	}
699
700	/// Verify all signatures submitted during the batching session.
701	#[must_use]
702	pub fn verify(mut self) -> bool {
703		self.0 = true;
704		tet_io::crypto::finish_batch_verify()
705	}
706}
707
708impl Drop for SignatureBatching {
709	fn drop(&mut self) {
710		// Sanity check. If user forgets to actually call `verify()`.
711		//
712		// We should not panic if the current thread is already panicking,
713		// because Rust otherwise aborts the process.
714		if !self.0 && !tetcore_std::thread::panicking() {
715			panic!("Signature verification has not been called before `SignatureBatching::drop`")
716		}
717	}
718}
719
720/// Describes on what should happen with a storage transaction.
721pub enum TransactionOutcome<R> {
722	/// Commit the transaction.
723	Commit(R),
724	/// Rollback the transaction.
725	Rollback(R),
726}
727
728impl<R> TransactionOutcome<R> {
729	/// Convert into the inner type.
730	pub fn into_inner(self) -> R {
731		match self {
732			Self::Commit(r) => r,
733			Self::Rollback(r) => r,
734		}
735	}
736}
737
738#[cfg(test)]
739mod tests {
740	use super::*;
741	use codec::{Encode, Decode};
742	use tet_core::crypto::Pair;
743
744	#[test]
745	fn opaque_extrinsic_serialization() {
746		let ex = super::OpaqueExtrinsic(vec![1, 2, 3, 4]);
747		assert_eq!(serde_json::to_string(&ex).unwrap(), "\"0x1001020304\"".to_owned());
748	}
749
750	#[test]
751	fn dispatch_error_encoding() {
752		let error = DispatchError::Module {
753			index: 1,
754			error: 2,
755			message: Some("error message"),
756		};
757		let encoded = error.encode();
758		let decoded = DispatchError::decode(&mut &encoded[..]).unwrap();
759		assert_eq!(encoded, vec![3, 1, 2]);
760		assert_eq!(
761			decoded,
762			DispatchError::Module {
763				index: 1,
764				error: 2,
765				message: None,
766			},
767		);
768	}
769
770	#[test]
771	fn multi_signature_ecdsa_verify_works() {
772		let msg = &b"test-message"[..];
773		let (pair, _) = ecdsa::Pair::generate();
774
775		let signature = pair.sign(&msg);
776		assert!(ecdsa::Pair::verify(&signature, msg, &pair.public()));
777
778		let multi_sig = MultiSignature::from(signature);
779		let multi_signer = MultiSigner::from(pair.public());
780		assert!(multi_sig.verify(msg, &multi_signer.into_account()));
781
782		let multi_signer = MultiSigner::from(pair.public());
783		assert!(multi_sig.verify(msg, &multi_signer.into_account()));
784	}
785
786
787	#[test]
788	#[should_panic(expected = "Signature verification has not been called")]
789	fn batching_still_finishes_when_not_called_directly() {
790		let mut ext = tp_state_machine::BasicExternalities::default();
791		ext.register_extension(
792			tet_core::traits::TaskExecutorExt::new(tet_core::testing::TaskExecutor::new()),
793		);
794
795		ext.execute_with(|| {
796			let _batching = SignatureBatching::start();
797			tet_io::crypto::sr25519_verify(
798				&Default::default(),
799				&Vec::new(),
800				&Default::default(),
801			);
802		});
803	}
804
805	#[test]
806	#[should_panic(expected = "Hey, I'm an error")]
807	fn batching_does_not_panic_while_thread_is_already_panicking() {
808		let mut ext = tp_state_machine::BasicExternalities::default();
809		ext.register_extension(
810			tet_core::traits::TaskExecutorExt::new(tet_core::testing::TaskExecutor::new()),
811		);
812
813		ext.execute_with(|| {
814			let _batching = SignatureBatching::start();
815			panic!("Hey, I'm an error");
816		});
817	}
818}