1use crate::{
21 generic::Digest,
22 scale_info::{StaticTypeInfo, TypeInfo},
23 transaction_validity::{
24 TransactionSource, TransactionValidity, TransactionValidityError, UnknownTransaction,
25 ValidTransaction,
26 },
27 DispatchResult, KeyTypeId, OpaqueExtrinsic,
28};
29use alloc::vec::Vec;
30use codec::{
31 Codec, Decode, DecodeWithMemTracking, Encode, EncodeLike, FullCodec, HasCompact, MaxEncodedLen,
32};
33#[doc(hidden)]
34pub use core::{fmt::Debug, marker::PhantomData};
35#[cfg(feature = "serde")]
36use serde::{de::DeserializeOwned, Deserialize, Serialize};
37use sp_application_crypto::AppCrypto;
38pub use sp_arithmetic::traits::{
39 checked_pow, ensure_pow, AtLeast32Bit, AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedDiv,
40 CheckedMul, CheckedShl, CheckedShr, CheckedSub, Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv,
41 EnsureDivAssign, EnsureFixedPointNumber, EnsureFrom, EnsureInto, EnsureMul, EnsureMulAssign,
42 EnsureOp, EnsureOpAssign, EnsureSub, EnsureSubAssign, IntegerSquareRoot, One,
43 SaturatedConversion, Saturating, UniqueSaturatedFrom, UniqueSaturatedInto, Zero,
44};
45use sp_core::{self, storage::StateVersion, Hasher, TypeId, U256};
46#[doc(hidden)]
47pub use sp_core::{
48 parameter_types, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstInt,
49 ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, ConstUint, Get, GetDefault, TryCollect,
50 TypedGet,
51};
52#[cfg(feature = "std")]
53use std::fmt::Display;
54#[cfg(feature = "std")]
55use std::str::FromStr;
56
57pub mod transaction_extension;
58pub mod vers_tx_ext;
59pub use transaction_extension::{
60 DispatchTransaction, Implication, ImplicationParts, TransactionExtension,
61 TransactionExtensionMetadata, TxBaseImplication, ValidateResult,
62};
63pub use vers_tx_ext::{
64 DecodeWithVersion, DecodeWithVersionWithMemTracking, ExtensionVariant, InvalidVersion,
65 MultiVersion, Pipeline, PipelineAtVers, PipelineMetadataBuilder, PipelineVersion,
66};
67
68pub trait Lazy<T: ?Sized> {
70 fn get(&mut self) -> &T;
74}
75
76impl<'a> Lazy<[u8]> for &'a [u8] {
77 fn get(&mut self) -> &[u8] {
78 self
79 }
80}
81
82pub trait IdentifyAccount {
85 type AccountId;
87 fn into_account(self) -> Self::AccountId;
89}
90
91impl IdentifyAccount for sp_core::ed25519::Public {
92 type AccountId = Self;
93 fn into_account(self) -> Self {
94 self
95 }
96}
97
98impl IdentifyAccount for sp_core::sr25519::Public {
99 type AccountId = Self;
100 fn into_account(self) -> Self {
101 self
102 }
103}
104
105impl IdentifyAccount for sp_core::ecdsa::Public {
106 type AccountId = Self;
107 fn into_account(self) -> Self {
108 self
109 }
110}
111
112#[cfg(feature = "bls-experimental")]
113impl IdentifyAccount for sp_core::ecdsa_bls381::Public {
114 type AccountId = Self;
115 fn into_account(self) -> Self {
116 self
117 }
118}
119
120pub trait Verify {
122 type Signer: IdentifyAccount;
124 fn verify<L: Lazy<[u8]>>(
128 &self,
129 msg: L,
130 signer: &<Self::Signer as IdentifyAccount>::AccountId,
131 ) -> bool;
132}
133
134impl Verify for sp_core::ed25519::Signature {
135 type Signer = sp_core::ed25519::Public;
136
137 fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &sp_core::ed25519::Public) -> bool {
138 sp_io::crypto::ed25519_verify(self, msg.get(), signer)
139 }
140}
141
142impl Verify for sp_core::sr25519::Signature {
143 type Signer = sp_core::sr25519::Public;
144
145 fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &sp_core::sr25519::Public) -> bool {
146 sp_io::crypto::sr25519_verify(self, msg.get(), signer)
147 }
148}
149
150impl Verify for sp_core::ecdsa::Signature {
151 type Signer = sp_core::ecdsa::Public;
152 fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &sp_core::ecdsa::Public) -> bool {
153 if !sp_core::ecdsa::is_signature_normalized(self.as_ref()) {
154 return false;
155 }
156 match sp_io::crypto::secp256k1_ecdsa_recover_compressed(
157 self.as_ref(),
158 &sp_io::hashing::blake2_256(msg.get()),
159 ) {
160 Ok(pubkey) => signer.0 == pubkey,
161 _ => false,
162 }
163 }
164}
165
166#[cfg(feature = "bls-experimental")]
167impl Verify for sp_core::ecdsa_bls381::Signature {
168 type Signer = sp_core::ecdsa_bls381::Public;
169 fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &sp_core::ecdsa_bls381::Public) -> bool {
170 <sp_core::ecdsa_bls381::Pair as sp_core::Pair>::verify(self, msg.get(), signer)
171 }
172}
173
174pub trait AppVerify {
176 type AccountId;
178 fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &Self::AccountId) -> bool;
180}
181
182impl<
183 S: Verify<Signer = <<T as AppCrypto>::Public as sp_application_crypto::AppPublic>::Generic>
184 + From<T>,
185 T: sp_application_crypto::Wraps<Inner = S>
186 + sp_application_crypto::AppCrypto
187 + sp_application_crypto::AppSignature
188 + AsRef<S>
189 + AsMut<S>
190 + From<S>,
191 > AppVerify for T
192where
193 <S as Verify>::Signer: IdentifyAccount<AccountId = <S as Verify>::Signer>,
194 <<T as AppCrypto>::Public as sp_application_crypto::AppPublic>::Generic: IdentifyAccount<
195 AccountId = <<T as AppCrypto>::Public as sp_application_crypto::AppPublic>::Generic,
196 >,
197{
198 type AccountId = <T as AppCrypto>::Public;
199 fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &<T as AppCrypto>::Public) -> bool {
200 use sp_application_crypto::IsWrappedBy;
201 let inner: &S = self.as_ref();
202 let inner_pubkey =
203 <<T as AppCrypto>::Public as sp_application_crypto::AppPublic>::Generic::from_ref(
204 signer,
205 );
206 Verify::verify(inner, msg, inner_pubkey)
207 }
208}
209
210#[derive(Encode, Decode, Debug)]
212pub struct BadOrigin;
213
214impl From<BadOrigin> for &'static str {
215 fn from(_: BadOrigin) -> &'static str {
216 "Bad origin"
217 }
218}
219
220#[derive(Encode, Decode, Debug)]
222pub struct LookupError;
223
224impl From<LookupError> for &'static str {
225 fn from(_: LookupError) -> &'static str {
226 "Can not lookup"
227 }
228}
229
230impl From<LookupError> for TransactionValidityError {
231 fn from(_: LookupError) -> Self {
232 UnknownTransaction::CannotLookup.into()
233 }
234}
235
236pub trait Lookup {
238 type Source;
240 type Target;
242 fn lookup(&self, s: Self::Source) -> Result<Self::Target, LookupError>;
244}
245
246pub trait StaticLookup {
250 type Source: Codec + Clone + PartialEq + Debug + TypeInfo;
252 type Target;
254 fn lookup(s: Self::Source) -> Result<Self::Target, LookupError>;
256 fn unlookup(t: Self::Target) -> Self::Source;
258}
259
260#[derive(Clone, Copy, PartialEq, Eq)]
262pub struct IdentityLookup<T>(PhantomData<T>);
263impl<T> Default for IdentityLookup<T> {
264 fn default() -> Self {
265 Self(PhantomData::<T>::default())
266 }
267}
268
269impl<T: Codec + Clone + PartialEq + Debug + TypeInfo> StaticLookup for IdentityLookup<T> {
270 type Source = T;
271 type Target = T;
272 fn lookup(x: T) -> Result<T, LookupError> {
273 Ok(x)
274 }
275 fn unlookup(x: T) -> T {
276 x
277 }
278}
279
280impl<T> Lookup for IdentityLookup<T> {
281 type Source = T;
282 type Target = T;
283 fn lookup(&self, x: T) -> Result<T, LookupError> {
284 Ok(x)
285 }
286}
287
288pub struct AccountIdLookup<AccountId, AccountIndex>(PhantomData<(AccountId, AccountIndex)>);
290impl<AccountId, AccountIndex> StaticLookup for AccountIdLookup<AccountId, AccountIndex>
291where
292 AccountId: Codec + Clone + PartialEq + Debug,
293 AccountIndex: Codec + Clone + PartialEq + Debug,
294 crate::MultiAddress<AccountId, AccountIndex>: Codec + StaticTypeInfo,
295{
296 type Source = crate::MultiAddress<AccountId, AccountIndex>;
297 type Target = AccountId;
298 fn lookup(x: Self::Source) -> Result<Self::Target, LookupError> {
299 match x {
300 crate::MultiAddress::Id(i) => Ok(i),
301 _ => Err(LookupError),
302 }
303 }
304 fn unlookup(x: Self::Target) -> Self::Source {
305 crate::MultiAddress::Id(x)
306 }
307}
308
309impl<A, B> StaticLookup for (A, B)
311where
312 A: StaticLookup,
313 B: StaticLookup<Source = A::Source, Target = A::Target>,
314{
315 type Source = A::Source;
316 type Target = A::Target;
317
318 fn lookup(x: Self::Source) -> Result<Self::Target, LookupError> {
319 A::lookup(x.clone()).or_else(|_| B::lookup(x))
320 }
321 fn unlookup(x: Self::Target) -> Self::Source {
322 A::unlookup(x)
323 }
324}
325
326pub trait Morph<A> {
329 type Outcome;
331
332 fn morph(a: A) -> Self::Outcome;
334}
335
336impl<T> Morph<T> for Identity {
338 type Outcome = T;
339 fn morph(a: T) -> T {
340 a
341 }
342}
343
344pub trait TryMorph<A> {
347 type Outcome;
349
350 fn try_morph(a: A) -> Result<Self::Outcome, ()>;
352}
353
354impl<T> TryMorph<T> for Identity {
356 type Outcome = T;
357 fn try_morph(a: T) -> Result<T, ()> {
358 Ok(a)
359 }
360}
361
362pub struct MorphInto<T>(core::marker::PhantomData<T>);
364impl<T, A: Into<T>> Morph<A> for MorphInto<T> {
365 type Outcome = T;
366 fn morph(a: A) -> T {
367 a.into()
368 }
369}
370
371pub struct TryMorphInto<T>(core::marker::PhantomData<T>);
373impl<T, A: TryInto<T>> TryMorph<A> for TryMorphInto<T> {
374 type Outcome = T;
375 fn try_morph(a: A) -> Result<T, ()> {
376 a.try_into().map_err(|_| ())
377 }
378}
379
380pub struct TakeFirst;
382impl<T1> Morph<(T1,)> for TakeFirst {
383 type Outcome = T1;
384 fn morph(a: (T1,)) -> T1 {
385 a.0
386 }
387}
388impl<T1, T2> Morph<(T1, T2)> for TakeFirst {
389 type Outcome = T1;
390 fn morph(a: (T1, T2)) -> T1 {
391 a.0
392 }
393}
394impl<T1, T2, T3> Morph<(T1, T2, T3)> for TakeFirst {
395 type Outcome = T1;
396 fn morph(a: (T1, T2, T3)) -> T1 {
397 a.0
398 }
399}
400impl<T1, T2, T3, T4> Morph<(T1, T2, T3, T4)> for TakeFirst {
401 type Outcome = T1;
402 fn morph(a: (T1, T2, T3, T4)) -> T1 {
403 a.0
404 }
405}
406
407#[macro_export]
443macro_rules! morph_types {
444 (
445 @DECL $( #[doc = $doc:expr] )* $vq:vis $name:ident ()
446 ) => {
447 $( #[doc = $doc] )* $vq struct $name;
448 };
449 (
450 @DECL $( #[doc = $doc:expr] )* $vq:vis $name:ident ( $( $bound_id:ident ),+ )
451 ) => {
452 $( #[doc = $doc] )*
453 $vq struct $name < $($bound_id,)* > ( $crate::traits::PhantomData< ( $($bound_id,)* ) > ) ;
454 };
455 (
456 @IMPL $name:ty : ( $( $bounds:tt )* ) ( $( $where:tt )* )
457 = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* }
458 ) => {
459 impl<$($bounds)*> $crate::traits::Morph<$var_type> for $name $( $where )? {
460 type Outcome = $outcome;
461 fn morph($var: $var_type) -> Self::Outcome { $( $ex )* }
462 }
463 };
464 (
465 @IMPL_TRY $name:ty : ( $( $bounds:tt )* ) ( $( $where:tt )* )
466 = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* }
467 ) => {
468 impl<$($bounds)*> $crate::traits::TryMorph<$var_type> for $name $( $where )? {
469 type Outcome = $outcome;
470 fn try_morph($var: $var_type) -> Result<Self::Outcome, ()> { $( $ex )* }
471 }
472 };
473 (
474 @IMPL $name:ty : () ( $( $where:tt )* )
475 = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* }
476 ) => {
477 impl $crate::traits::Morph<$var_type> for $name $( $where )? {
478 type Outcome = $outcome;
479 fn morph($var: $var_type) -> Self::Outcome { $( $ex )* }
480 }
481 };
482 (
483 @IMPL_TRY $name:ty : () ( $( $where:tt )* )
484 = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* }
485 ) => {
486 impl $crate::traits::TryMorph<$var_type> for $name $( $where )? {
487 type Outcome = $outcome;
488 fn try_morph($var: $var_type) -> Result<Self::Outcome, ()> { $( $ex )* }
489 }
490 };
491 (
492 @IMPL_BOTH $name:ty : ( $( $bounds:tt )* ) ( $( $where:tt )* )
493 = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* }
494 ) => {
495 morph_types! {
496 @IMPL $name : ($($bounds)*) ($($where)*)
497 = |$var: $var_type| -> $outcome { $( $ex )* }
498 }
499 morph_types! {
500 @IMPL_TRY $name : ($($bounds)*) ($($where)*)
501 = |$var: $var_type| -> $outcome { Ok({$( $ex )*}) }
502 }
503 };
504
505 (
506 $( #[doc = $doc:expr] )* $vq:vis type $name:ident
507 $( < $( $bound_id:ident $( : $bound_head:path $( | $bound_tail:path )* )? ),+ > )?
508 $(: $type:tt)?
509 = |_| -> $outcome:ty { $( $ex:expr )* };
510 $( $rest:tt )*
511 ) => {
512 morph_types! {
513 $( #[doc = $doc] )* $vq type $name
514 $( < $( $bound_id $( : $bound_head $( | $bound_tail )* )? ),+ > )?
515 EXTRA_GENERIC(X)
516 $(: $type)?
517 = |_x: X| -> $outcome { $( $ex )* };
518 $( $rest )*
519 }
520 };
521 (
522 $( #[doc = $doc:expr] )* $vq:vis type $name:ident
523 $( < $( $bound_id:ident $( : $bound_head:path $( | $bound_tail:path )* )? ),+ > )?
524 $( EXTRA_GENERIC ($extra:ident) )?
525 = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* }
526 $( where $( $where_path:ty : $where_bound_head:path $( | $where_bound_tail:path )* ),* )?;
527 $( $rest:tt )*
528 ) => {
529 morph_types! { @DECL $( #[doc = $doc] )* $vq $name ( $( $( $bound_id ),+ )? ) }
530 morph_types! {
531 @IMPL_BOTH $name $( < $( $bound_id ),* > )? :
532 ( $( $( $bound_id $( : $bound_head $( + $bound_tail )* )? , )+ )? $( $extra )? )
533 ( $( where $( $where_path : $where_bound_head $( + $where_bound_tail )* ),* )? )
534 = |$var: $var_type| -> $outcome { $( $ex )* }
535 }
536 morph_types!{ $($rest)* }
537 };
538 (
539 $( #[doc = $doc:expr] )* $vq:vis type $name:ident
540 $( < $( $bound_id:ident $( : $bound_head:path $( | $bound_tail:path )* )? ),+ > )?
541 $( EXTRA_GENERIC ($extra:ident) )?
542 : Morph
543 = |$var:ident: $var_type:ty| -> $outcome:ty { $( $ex:expr )* }
544 $( where $( $where_path:ty : $where_bound_head:path $( | $where_bound_tail:path )* ),* )?;
545 $( $rest:tt )*
546 ) => {
547 morph_types! { @DECL $( #[doc = $doc] )* $vq $name ( $( $( $bound_id ),+ )? ) }
548 morph_types! {
549 @IMPL $name $( < $( $bound_id ),* > )? :
550 ( $( $( $bound_id $( : $bound_head $( + $bound_tail )* )? , )+ )? $( $extra )? )
551 ( $( where $( $where_path : $where_bound_head $( + $where_bound_tail )* ),* )? )
552 = |$var: $var_type| -> $outcome { $( $ex )* }
553 }
554 morph_types!{ $($rest)* }
555 };
556 (
557 $( #[doc = $doc:expr] )* $vq:vis type $name:ident
558 $( < $( $bound_id:ident $( : $bound_head:path $( | $bound_tail:path )* )? ),+ > )?
559 $( EXTRA_GENERIC ($extra:ident) )?
560 : TryMorph
561 = |$var:ident: $var_type:ty| -> Result<$outcome:ty, ()> { $( $ex:expr )* }
562 $( where $( $where_path:ty : $where_bound_head:path $( | $where_bound_tail:path )* ),* )?;
563 $( $rest:tt )*
564 ) => {
565 morph_types! { @DECL $( #[doc = $doc] )* $vq $name ( $( $( $bound_id ),+ )? ) }
566 morph_types! {
567 @IMPL_TRY $name $( < $( $bound_id ),* > )? :
568 ( $( $( $bound_id $( : $bound_head $( + $bound_tail )* )? , )+ )? $( $extra )? )
569 ( $( where $( $where_path : $where_bound_head $( + $where_bound_tail )* ),* )? )
570 = |$var: $var_type| -> $outcome { $( $ex )* }
571 }
572 morph_types!{ $($rest)* }
573 };
574 () => {}
575}
576
577morph_types! {
578 pub type Replace<V: TypedGet> = |_| -> V::Type { V::get() };
580
581 pub type ReplaceWithDefault<V: Default> = |_| -> V { Default::default() };
583
584 pub type ReduceBy<N: TypedGet> = |r: N::Type| -> N::Type {
586 r.checked_sub(&N::get()).unwrap_or(Zero::zero())
587 } where N::Type: CheckedSub | Zero;
588
589 pub type CheckedReduceBy<N: TypedGet>: TryMorph = |r: N::Type| -> Result<N::Type, ()> {
592 r.checked_sub(&N::get()).ok_or(())
593 } where N::Type: CheckedSub;
594
595 pub type MorphWithUpperLimit<L: TypedGet, M>: TryMorph = |r: L::Type| -> Result<L::Type, ()> {
597 M::try_morph(r).map(|m| m.min(L::get()))
598 } where L::Type: Ord, M: TryMorph<L::Type, Outcome = L::Type>;
599}
600
601pub trait Convert<A, B> {
603 fn convert(a: A) -> B;
605}
606
607impl<A, B: Default> Convert<A, B> for () {
608 fn convert(_: A) -> B {
609 Default::default()
610 }
611}
612
613pub trait ConvertBack<A, B>: Convert<A, B> {
617 fn convert_back(b: B) -> A;
619}
620
621pub trait MaybeConvert<A, B> {
623 fn maybe_convert(a: A) -> Option<B>;
625}
626
627#[impl_trait_for_tuples::impl_for_tuples(30)]
628impl<A: Clone, B> MaybeConvert<A, B> for Tuple {
629 fn maybe_convert(a: A) -> Option<B> {
630 for_tuples!( #(
631 match Tuple::maybe_convert(a.clone()) {
632 Some(b) => return Some(b),
633 None => {},
634 }
635 )* );
636 None
637 }
638}
639
640pub trait MaybeConvertBack<A, B>: MaybeConvert<A, B> {
643 fn maybe_convert_back(b: B) -> Option<A>;
645}
646
647#[impl_trait_for_tuples::impl_for_tuples(30)]
648impl<A: Clone, B: Clone> MaybeConvertBack<A, B> for Tuple {
649 fn maybe_convert_back(b: B) -> Option<A> {
650 for_tuples!( #(
651 match Tuple::maybe_convert_back(b.clone()) {
652 Some(a) => return Some(a),
653 None => {},
654 }
655 )* );
656 None
657 }
658}
659
660pub trait TryConvert<A, B> {
663 fn try_convert(a: A) -> Result<B, A>;
665}
666
667#[impl_trait_for_tuples::impl_for_tuples(30)]
668impl<A, B> TryConvert<A, B> for Tuple {
669 fn try_convert(a: A) -> Result<B, A> {
670 for_tuples!( #(
671 let a = match Tuple::try_convert(a) {
672 Ok(b) => return Ok(b),
673 Err(a) => a,
674 };
675 )* );
676 Err(a)
677 }
678}
679
680pub trait TryConvertBack<A, B>: TryConvert<A, B> {
683 fn try_convert_back(b: B) -> Result<A, B>;
686}
687
688#[impl_trait_for_tuples::impl_for_tuples(30)]
689impl<A, B> TryConvertBack<A, B> for Tuple {
690 fn try_convert_back(b: B) -> Result<A, B> {
691 for_tuples!( #(
692 let b = match Tuple::try_convert_back(b) {
693 Ok(a) => return Ok(a),
694 Err(b) => b,
695 };
696 )* );
697 Err(b)
698 }
699}
700
701pub trait MaybeEquivalence<A, B> {
703 fn convert(a: &A) -> Option<B>;
705 fn convert_back(b: &B) -> Option<A>;
707}
708
709#[impl_trait_for_tuples::impl_for_tuples(30)]
710impl<A, B> MaybeEquivalence<A, B> for Tuple {
711 fn convert(a: &A) -> Option<B> {
712 for_tuples!( #(
713 match Tuple::convert(a) {
714 Some(b) => return Some(b),
715 None => {},
716 }
717 )* );
718 None
719 }
720 fn convert_back(b: &B) -> Option<A> {
721 for_tuples!( #(
722 match Tuple::convert_back(b) {
723 Some(a) => return Some(a),
724 None => {},
725 }
726 )* );
727 None
728 }
729}
730
731pub struct ConvertToValue<T>(core::marker::PhantomData<T>);
734impl<X, Y, T: Get<Y>> Convert<X, Y> for ConvertToValue<T> {
735 fn convert(_: X) -> Y {
736 T::get()
737 }
738}
739impl<X, Y, T: Get<Y>> MaybeConvert<X, Y> for ConvertToValue<T> {
740 fn maybe_convert(_: X) -> Option<Y> {
741 Some(T::get())
742 }
743}
744impl<X, Y, T: Get<Y>> MaybeConvertBack<X, Y> for ConvertToValue<T> {
745 fn maybe_convert_back(_: Y) -> Option<X> {
746 None
747 }
748}
749impl<X, Y, T: Get<Y>> TryConvert<X, Y> for ConvertToValue<T> {
750 fn try_convert(_: X) -> Result<Y, X> {
751 Ok(T::get())
752 }
753}
754impl<X, Y, T: Get<Y>> TryConvertBack<X, Y> for ConvertToValue<T> {
755 fn try_convert_back(y: Y) -> Result<X, Y> {
756 Err(y)
757 }
758}
759impl<X, Y, T: Get<Y>> MaybeEquivalence<X, Y> for ConvertToValue<T> {
760 fn convert(_: &X) -> Option<Y> {
761 Some(T::get())
762 }
763 fn convert_back(_: &Y) -> Option<X> {
764 None
765 }
766}
767
768pub struct Identity;
770impl<T> Convert<T, T> for Identity {
771 fn convert(a: T) -> T {
772 a
773 }
774}
775impl<T> ConvertBack<T, T> for Identity {
776 fn convert_back(a: T) -> T {
777 a
778 }
779}
780impl<T> MaybeConvert<T, T> for Identity {
781 fn maybe_convert(a: T) -> Option<T> {
782 Some(a)
783 }
784}
785impl<T> MaybeConvertBack<T, T> for Identity {
786 fn maybe_convert_back(a: T) -> Option<T> {
787 Some(a)
788 }
789}
790impl<T> TryConvert<T, T> for Identity {
791 fn try_convert(a: T) -> Result<T, T> {
792 Ok(a)
793 }
794}
795impl<T> TryConvertBack<T, T> for Identity {
796 fn try_convert_back(a: T) -> Result<T, T> {
797 Ok(a)
798 }
799}
800impl<T: Clone> MaybeEquivalence<T, T> for Identity {
801 fn convert(a: &T) -> Option<T> {
802 Some(a.clone())
803 }
804 fn convert_back(a: &T) -> Option<T> {
805 Some(a.clone())
806 }
807}
808
809pub struct ConvertInto;
811impl<A: Into<B>, B> Convert<A, B> for ConvertInto {
812 fn convert(a: A) -> B {
813 a.into()
814 }
815}
816impl<A: Into<B>, B> MaybeConvert<A, B> for ConvertInto {
817 fn maybe_convert(a: A) -> Option<B> {
818 Some(a.into())
819 }
820}
821impl<A: Into<B>, B: Into<A>> MaybeConvertBack<A, B> for ConvertInto {
822 fn maybe_convert_back(b: B) -> Option<A> {
823 Some(b.into())
824 }
825}
826impl<A: Into<B>, B> TryConvert<A, B> for ConvertInto {
827 fn try_convert(a: A) -> Result<B, A> {
828 Ok(a.into())
829 }
830}
831impl<A: Into<B>, B: Into<A>> TryConvertBack<A, B> for ConvertInto {
832 fn try_convert_back(b: B) -> Result<A, B> {
833 Ok(b.into())
834 }
835}
836impl<A: Clone + Into<B>, B: Clone + Into<A>> MaybeEquivalence<A, B> for ConvertInto {
837 fn convert(a: &A) -> Option<B> {
838 Some(a.clone().into())
839 }
840 fn convert_back(b: &B) -> Option<A> {
841 Some(b.clone().into())
842 }
843}
844
845pub struct TryConvertInto;
847impl<A: Clone + TryInto<B>, B> MaybeConvert<A, B> for TryConvertInto {
848 fn maybe_convert(a: A) -> Option<B> {
849 a.clone().try_into().ok()
850 }
851}
852impl<A: Clone + TryInto<B>, B: Clone + TryInto<A>> MaybeConvertBack<A, B> for TryConvertInto {
853 fn maybe_convert_back(b: B) -> Option<A> {
854 b.clone().try_into().ok()
855 }
856}
857impl<A: Clone + TryInto<B>, B> TryConvert<A, B> for TryConvertInto {
858 fn try_convert(a: A) -> Result<B, A> {
859 a.clone().try_into().map_err(|_| a)
860 }
861}
862impl<A: Clone + TryInto<B>, B: Clone + TryInto<A>> TryConvertBack<A, B> for TryConvertInto {
863 fn try_convert_back(b: B) -> Result<A, B> {
864 b.clone().try_into().map_err(|_| b)
865 }
866}
867impl<A: Clone + TryInto<B>, B: Clone + TryInto<A>> MaybeEquivalence<A, B> for TryConvertInto {
868 fn convert(a: &A) -> Option<B> {
869 a.clone().try_into().ok()
870 }
871 fn convert_back(b: &B) -> Option<A> {
872 b.clone().try_into().ok()
873 }
874}
875
876pub trait CheckedConversion {
880 fn checked_from<T>(t: T) -> Option<Self>
886 where
887 Self: TryFrom<T>,
888 {
889 <Self as TryFrom<T>>::try_from(t).ok()
890 }
891 fn checked_into<T>(self) -> Option<T>
897 where
898 Self: TryInto<T>,
899 {
900 <Self as TryInto<T>>::try_into(self).ok()
901 }
902}
903impl<T: Sized> CheckedConversion for T {}
904
905pub trait Scale<Other> {
908 type Output;
910
911 fn mul(self, other: Other) -> Self::Output;
913
914 fn div(self, other: Other) -> Self::Output;
916
917 fn rem(self, other: Other) -> Self::Output;
919}
920macro_rules! impl_scale {
921 ($self:ty, $other:ty) => {
922 impl Scale<$other> for $self {
923 type Output = Self;
924 fn mul(self, other: $other) -> Self::Output {
925 self * (other as Self)
926 }
927 fn div(self, other: $other) -> Self::Output {
928 self / (other as Self)
929 }
930 fn rem(self, other: $other) -> Self::Output {
931 self % (other as Self)
932 }
933 }
934 };
935}
936impl_scale!(u128, u128);
937impl_scale!(u128, u64);
938impl_scale!(u128, u32);
939impl_scale!(u128, u16);
940impl_scale!(u128, u8);
941impl_scale!(u64, u64);
942impl_scale!(u64, u32);
943impl_scale!(u64, u16);
944impl_scale!(u64, u8);
945impl_scale!(u32, u32);
946impl_scale!(u32, u16);
947impl_scale!(u32, u8);
948impl_scale!(u16, u16);
949impl_scale!(u16, u8);
950impl_scale!(u8, u8);
951
952pub trait Clear {
955 fn is_clear(&self) -> bool;
957
958 fn clear() -> Self;
960}
961
962impl<T: Default + Eq + PartialEq> Clear for T {
963 fn is_clear(&self) -> bool {
964 *self == Self::clear()
965 }
966 fn clear() -> Self {
967 Default::default()
968 }
969}
970
971pub trait SimpleBitOps:
973 Sized
974 + Clear
975 + core::ops::BitOr<Self, Output = Self>
976 + core::ops::BitXor<Self, Output = Self>
977 + core::ops::BitAnd<Self, Output = Self>
978{
979}
980impl<
981 T: Sized
982 + Clear
983 + core::ops::BitOr<Self, Output = Self>
984 + core::ops::BitXor<Self, Output = Self>
985 + core::ops::BitAnd<Self, Output = Self>,
986 > SimpleBitOps for T
987{
988}
989
990pub trait Hash:
994 'static
995 + MaybeSerializeDeserialize
996 + Debug
997 + Clone
998 + Eq
999 + PartialEq
1000 + Hasher<Out = <Self as Hash>::Output>
1001{
1002 type Output: HashOutput;
1004
1005 fn hash(s: &[u8]) -> Self::Output {
1007 <Self as Hasher>::hash(s)
1008 }
1009
1010 fn hash_of<S: Encode>(s: &S) -> Self::Output {
1012 Encode::using_encoded(s, <Self as Hasher>::hash)
1013 }
1014
1015 fn ordered_trie_root(input: Vec<Vec<u8>>, state_version: StateVersion) -> Self::Output;
1017
1018 fn trie_root(input: Vec<(Vec<u8>, Vec<u8>)>, state_version: StateVersion) -> Self::Output;
1020}
1021
1022pub trait HashOutput:
1024 Member
1025 + MaybeSerializeDeserialize
1026 + MaybeDisplay
1027 + MaybeFromStr
1028 + Debug
1029 + core::hash::Hash
1030 + AsRef<[u8]>
1031 + AsMut<[u8]>
1032 + Copy
1033 + Ord
1034 + Default
1035 + Encode
1036 + Decode
1037 + DecodeWithMemTracking
1038 + EncodeLike
1039 + MaxEncodedLen
1040 + TypeInfo
1041{
1042}
1043
1044impl<T> HashOutput for T where
1045 T: Member
1046 + MaybeSerializeDeserialize
1047 + MaybeDisplay
1048 + MaybeFromStr
1049 + Debug
1050 + core::hash::Hash
1051 + AsRef<[u8]>
1052 + AsMut<[u8]>
1053 + Copy
1054 + Ord
1055 + Default
1056 + Encode
1057 + Decode
1058 + DecodeWithMemTracking
1059 + EncodeLike
1060 + MaxEncodedLen
1061 + TypeInfo
1062{
1063}
1064
1065#[derive(PartialEq, Eq, Clone, Debug, TypeInfo)]
1067#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1068pub struct BlakeTwo256;
1069
1070impl Hasher for BlakeTwo256 {
1071 type Out = sp_core::H256;
1072 type StdHasher = hash256_std_hasher::Hash256StdHasher;
1073 const LENGTH: usize = 32;
1074
1075 fn hash(s: &[u8]) -> Self::Out {
1076 sp_io::hashing::blake2_256(s).into()
1077 }
1078}
1079
1080impl Hash for BlakeTwo256 {
1081 type Output = sp_core::H256;
1082
1083 fn ordered_trie_root(input: Vec<Vec<u8>>, version: StateVersion) -> Self::Output {
1084 sp_io::trie::blake2_256_ordered_root(input, version)
1085 }
1086
1087 fn trie_root(input: Vec<(Vec<u8>, Vec<u8>)>, version: StateVersion) -> Self::Output {
1088 sp_io::trie::blake2_256_root(input, version)
1089 }
1090}
1091
1092#[derive(PartialEq, Eq, Clone, Debug, TypeInfo)]
1094#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1095pub struct Keccak256;
1096
1097impl Hasher for Keccak256 {
1098 type Out = sp_core::H256;
1099 type StdHasher = hash256_std_hasher::Hash256StdHasher;
1100 const LENGTH: usize = 32;
1101
1102 fn hash(s: &[u8]) -> Self::Out {
1103 sp_io::hashing::keccak_256(s).into()
1104 }
1105}
1106
1107impl Hash for Keccak256 {
1108 type Output = sp_core::H256;
1109
1110 fn ordered_trie_root(input: Vec<Vec<u8>>, version: StateVersion) -> Self::Output {
1111 sp_io::trie::keccak_256_ordered_root(input, version)
1112 }
1113
1114 fn trie_root(input: Vec<(Vec<u8>, Vec<u8>)>, version: StateVersion) -> Self::Output {
1115 sp_io::trie::keccak_256_root(input, version)
1116 }
1117}
1118
1119pub trait CheckEqual {
1121 fn check_equal(&self, other: &Self);
1123}
1124
1125impl CheckEqual for sp_core::H256 {
1126 #[cfg(feature = "std")]
1127 fn check_equal(&self, other: &Self) {
1128 use sp_core::hexdisplay::HexDisplay;
1129 if self != other {
1130 println!(
1131 "Hash: given={}, expected={}",
1132 HexDisplay::from(self.as_fixed_bytes()),
1133 HexDisplay::from(other.as_fixed_bytes()),
1134 );
1135 }
1136 }
1137
1138 #[cfg(not(feature = "std"))]
1139 fn check_equal(&self, other: &Self) {
1140 if self != other {
1141 log::error!("Hash not equal: given={:?}, expected={:?}", self, other);
1142 }
1143 }
1144}
1145
1146impl CheckEqual for super::generic::DigestItem {
1147 #[cfg(feature = "std")]
1148 fn check_equal(&self, other: &Self) {
1149 if self != other {
1150 println!("DigestItem: given={:?}, expected={:?}", self, other);
1151 }
1152 }
1153
1154 #[cfg(not(feature = "std"))]
1155 fn check_equal(&self, other: &Self) {
1156 if self != other {
1157 log::error!("DigestItem not equal: given={:?}, expected={:?}", self, other);
1158 }
1159 }
1160}
1161
1162sp_core::impl_maybe_marker!(
1163 trait MaybeDisplay: Display;
1165
1166 trait MaybeFromStr: FromStr;
1168
1169 trait MaybeHash: core::hash::Hash;
1171);
1172
1173sp_core::impl_maybe_marker_std_or_serde!(
1174 trait MaybeSerialize: Serialize;
1176
1177 trait MaybeSerializeDeserialize: DeserializeOwned, Serialize;
1179);
1180
1181pub trait Member: Send + Sync + Sized + Debug + Eq + PartialEq + Clone + 'static {}
1183impl<T: Send + Sync + Sized + Debug + Eq + PartialEq + Clone + 'static> Member for T {}
1184
1185pub trait IsMember<MemberId> {
1187 fn is_member(member_id: &MemberId) -> bool;
1189}
1190
1191pub trait BlockNumber:
1193 Member
1194 + MaybeSerializeDeserialize
1195 + MaybeFromStr
1196 + Debug
1197 + core::hash::Hash
1198 + Copy
1199 + MaybeDisplay
1200 + AtLeast32BitUnsigned
1201 + Into<U256>
1202 + TryFrom<U256>
1203 + Default
1204 + TypeInfo
1205 + MaxEncodedLen
1206 + FullCodec
1207 + DecodeWithMemTracking
1208 + HasCompact<Type: DecodeWithMemTracking>
1209{
1210}
1211
1212impl<
1213 T: Member
1214 + MaybeSerializeDeserialize
1215 + MaybeFromStr
1216 + Debug
1217 + core::hash::Hash
1218 + Copy
1219 + MaybeDisplay
1220 + AtLeast32BitUnsigned
1221 + Into<U256>
1222 + TryFrom<U256>
1223 + Default
1224 + TypeInfo
1225 + MaxEncodedLen
1226 + FullCodec
1227 + DecodeWithMemTracking
1228 + HasCompact<Type: DecodeWithMemTracking>,
1229 > BlockNumber for T
1230{
1231}
1232
1233pub trait Header:
1239 Clone
1240 + Send
1241 + Sync
1242 + Codec
1243 + DecodeWithMemTracking
1244 + Eq
1245 + MaybeSerialize
1246 + Debug
1247 + TypeInfo
1248 + 'static
1249{
1250 type Number: BlockNumber;
1252 type Hash: HashOutput;
1254 type Hashing: Hash<Output = Self::Hash>;
1256
1257 fn new(
1259 number: Self::Number,
1260 extrinsics_root: Self::Hash,
1261 state_root: Self::Hash,
1262 parent_hash: Self::Hash,
1263 digest: Digest,
1264 ) -> Self;
1265
1266 fn number(&self) -> &Self::Number;
1268 fn set_number(&mut self, number: Self::Number);
1270
1271 fn extrinsics_root(&self) -> &Self::Hash;
1273 fn set_extrinsics_root(&mut self, root: Self::Hash);
1275
1276 fn state_root(&self) -> &Self::Hash;
1278 fn set_state_root(&mut self, root: Self::Hash);
1280
1281 fn parent_hash(&self) -> &Self::Hash;
1283 fn set_parent_hash(&mut self, hash: Self::Hash);
1285
1286 fn digest(&self) -> &Digest;
1288 fn digest_mut(&mut self) -> &mut Digest;
1290
1291 fn hash(&self) -> Self::Hash {
1293 <Self::Hashing as Hash>::hash_of(self)
1294 }
1295}
1296
1297#[doc(hidden)]
1317pub trait HeaderProvider {
1318 type HeaderT: Header;
1320}
1321
1322pub trait LazyExtrinsic: Sized {
1324 fn decode_unprefixed(data: &[u8]) -> Result<Self, codec::Error>;
1332}
1333
1334pub trait LazyBlock: Debug + Encode + Decode + Sized {
1336 type Extrinsic: LazyExtrinsic;
1338 type Header: Header;
1340
1341 fn header(&self) -> &Self::Header;
1343
1344 fn header_mut(&mut self) -> &mut Self::Header;
1346
1347 fn extrinsics(&self) -> impl Iterator<Item = Result<Self::Extrinsic, codec::Error>>;
1351}
1352
1353pub trait Block:
1358 HeaderProvider<HeaderT = Self::Header>
1359 + Into<Self::LazyBlock>
1360 + EncodeLike<Self::LazyBlock>
1361 + Clone
1362 + Send
1363 + Sync
1364 + Codec
1365 + DecodeWithMemTracking
1366 + Eq
1367 + MaybeSerialize
1368 + Debug
1369 + 'static
1370{
1371 type Extrinsic: Member + Codec + ExtrinsicLike + MaybeSerialize + Into<OpaqueExtrinsic>;
1373 type Header: Header<Hash = Self::Hash> + MaybeSerializeDeserialize;
1375 type Hash: HashOutput;
1377
1378 type LazyBlock: LazyBlock<Extrinsic = Self::Extrinsic, Header = Self::Header> + EncodeLike<Self>;
1381
1382 fn header(&self) -> &Self::Header;
1384 fn extrinsics(&self) -> &[Self::Extrinsic];
1386 fn deconstruct(self) -> (Self::Header, Vec<Self::Extrinsic>);
1388 fn new(header: Self::Header, extrinsics: Vec<Self::Extrinsic>) -> Self;
1390 fn hash(&self) -> Self::Hash {
1392 <<Self::Header as Header>::Hashing as Hash>::hash_of(self.header())
1393 }
1394}
1395
1396#[deprecated = "Use `ExtrinsicLike` along with the `CreateTransaction` trait family instead"]
1398pub trait Extrinsic: Sized {
1399 type Call: TypeInfo;
1401
1402 type SignaturePayload: SignaturePayload;
1408
1409 fn is_signed(&self) -> Option<bool> {
1412 None
1413 }
1414
1415 fn is_bare(&self) -> bool {
1417 !self.is_signed().unwrap_or(true)
1418 }
1419
1420 fn new(_call: Self::Call, _signed_data: Option<Self::SignaturePayload>) -> Option<Self> {
1423 None
1424 }
1425}
1426
1427pub trait ExtrinsicLike: Sized {
1429 #[deprecated = "Use and implement `!is_bare()` instead"]
1432 fn is_signed(&self) -> Option<bool> {
1433 None
1434 }
1435
1436 fn is_bare(&self) -> bool {
1438 #[allow(deprecated)]
1439 !self.is_signed().unwrap_or(true)
1440 }
1441}
1442
1443#[allow(deprecated)]
1444impl<T> ExtrinsicLike for T
1445where
1446 T: Extrinsic,
1447{
1448 fn is_signed(&self) -> Option<bool> {
1449 #[allow(deprecated)]
1450 <Self as Extrinsic>::is_signed(&self)
1451 }
1452
1453 fn is_bare(&self) -> bool {
1454 <Self as Extrinsic>::is_bare(&self)
1455 }
1456}
1457
1458pub trait ExtrinsicCall: ExtrinsicLike {
1460 type Call;
1462
1463 fn call(&self) -> &Self::Call;
1465
1466 fn into_call(self) -> Self::Call;
1468}
1469
1470pub trait SignaturePayload {
1473 type SignatureAddress: TypeInfo;
1477
1478 type Signature: TypeInfo;
1482
1483 type SignatureExtra: TypeInfo;
1487}
1488
1489impl SignaturePayload for () {
1490 type SignatureAddress = ();
1491 type Signature = ();
1492 type SignatureExtra = ();
1493}
1494
1495pub trait ExtrinsicMetadata {
1497 const VERSIONS: &'static [u8];
1501
1502 type TransactionExtensionPipelines;
1509}
1510
1511pub type HashingFor<B> = <<B as Block>::Header as Header>::Hashing;
1513pub type NumberFor<B> = <<B as Block>::Header as Header>::Number;
1515pub trait Checkable<Context>: Sized {
1522 type Checked;
1524
1525 fn check(self, c: &Context) -> Result<Self::Checked, TransactionValidityError>;
1527
1528 #[cfg(feature = "try-runtime")]
1537 fn unchecked_into_checked_i_know_what_i_am_doing(
1538 self,
1539 c: &Context,
1540 ) -> Result<Self::Checked, TransactionValidityError>;
1541}
1542
1543pub trait BlindCheckable: Sized {
1548 type Checked;
1550
1551 fn check(self) -> Result<Self::Checked, TransactionValidityError>;
1553}
1554
1555impl<T: BlindCheckable, Context> Checkable<Context> for T {
1557 type Checked = <Self as BlindCheckable>::Checked;
1558
1559 fn check(self, _c: &Context) -> Result<Self::Checked, TransactionValidityError> {
1560 BlindCheckable::check(self)
1561 }
1562
1563 #[cfg(feature = "try-runtime")]
1564 fn unchecked_into_checked_i_know_what_i_am_doing(
1565 self,
1566 _: &Context,
1567 ) -> Result<Self::Checked, TransactionValidityError> {
1568 unreachable!();
1569 }
1570}
1571
1572pub trait RefundWeight {
1574 fn refund(&mut self, weight: sp_weights::Weight);
1576}
1577
1578pub trait ExtensionPostDispatchWeightHandler<DispatchInfo>: RefundWeight {
1581 fn set_extension_weight(&mut self, info: &DispatchInfo);
1583}
1584
1585impl RefundWeight for () {
1586 fn refund(&mut self, _weight: sp_weights::Weight) {}
1587}
1588
1589impl ExtensionPostDispatchWeightHandler<()> for () {
1590 fn set_extension_weight(&mut self, _info: &()) {}
1591}
1592
1593pub trait Dispatchable {
1596 type RuntimeOrigin: Debug;
1600 type Config;
1602 type Info;
1606 type PostInfo: Eq
1609 + PartialEq
1610 + Clone
1611 + Copy
1612 + Encode
1613 + Decode
1614 + ExtensionPostDispatchWeightHandler<Self::Info>;
1615 fn dispatch(self, origin: Self::RuntimeOrigin)
1617 -> crate::DispatchResultWithInfo<Self::PostInfo>;
1618}
1619
1620pub type DispatchOriginOf<T> = <T as Dispatchable>::RuntimeOrigin;
1622pub type DispatchInfoOf<T> = <T as Dispatchable>::Info;
1624pub type PostDispatchInfoOf<T> = <T as Dispatchable>::PostInfo;
1626
1627impl Dispatchable for () {
1628 type RuntimeOrigin = ();
1629 type Config = ();
1630 type Info = ();
1631 type PostInfo = ();
1632 fn dispatch(
1633 self,
1634 _origin: Self::RuntimeOrigin,
1635 ) -> crate::DispatchResultWithInfo<Self::PostInfo> {
1636 panic!("This implementation should not be used for actual dispatch.");
1637 }
1638}
1639
1640#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
1642pub struct FakeDispatchable<Inner>(pub Inner);
1643impl<Inner> From<Inner> for FakeDispatchable<Inner> {
1644 fn from(inner: Inner) -> Self {
1645 Self(inner)
1646 }
1647}
1648impl<Inner> FakeDispatchable<Inner> {
1649 pub fn deconstruct(self) -> Inner {
1651 self.0
1652 }
1653}
1654impl<Inner> AsRef<Inner> for FakeDispatchable<Inner> {
1655 fn as_ref(&self) -> &Inner {
1656 &self.0
1657 }
1658}
1659
1660impl<Inner> Dispatchable for FakeDispatchable<Inner> {
1661 type RuntimeOrigin = ();
1662 type Config = ();
1663 type Info = ();
1664 type PostInfo = ();
1665 fn dispatch(
1666 self,
1667 _origin: Self::RuntimeOrigin,
1668 ) -> crate::DispatchResultWithInfo<Self::PostInfo> {
1669 panic!("This implementation should not be used for actual dispatch.");
1670 }
1671}
1672
1673pub trait AsSystemOriginSigner<AccountId> {
1675 fn as_system_origin_signer(&self) -> Option<&AccountId>;
1678}
1679
1680pub trait AsTransactionAuthorizedOrigin {
1694 fn is_transaction_authorized(&self) -> bool;
1704}
1705
1706#[deprecated = "Use `TransactionExtension` instead."]
1709pub trait SignedExtension:
1710 Codec + DecodeWithMemTracking + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo
1711{
1712 const IDENTIFIER: &'static str;
1717
1718 type AccountId;
1720
1721 type Call: Dispatchable;
1723
1724 type AdditionalSigned: Codec + TypeInfo;
1727
1728 type Pre;
1730
1731 fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError>;
1734
1735 fn validate(
1745 &self,
1746 _who: &Self::AccountId,
1747 _call: &Self::Call,
1748 _info: &DispatchInfoOf<Self::Call>,
1749 _len: usize,
1750 ) -> TransactionValidity {
1751 Ok(ValidTransaction::default())
1752 }
1753
1754 fn pre_dispatch(
1758 self,
1759 who: &Self::AccountId,
1760 call: &Self::Call,
1761 info: &DispatchInfoOf<Self::Call>,
1762 len: usize,
1763 ) -> Result<Self::Pre, TransactionValidityError>;
1764
1765 fn post_dispatch(
1782 _pre: Option<Self::Pre>,
1783 _info: &DispatchInfoOf<Self::Call>,
1784 _post_info: &PostDispatchInfoOf<Self::Call>,
1785 _len: usize,
1786 _result: &DispatchResult,
1787 ) -> Result<(), TransactionValidityError> {
1788 Ok(())
1789 }
1790
1791 fn metadata() -> Vec<TransactionExtensionMetadata> {
1800 alloc::vec![TransactionExtensionMetadata {
1801 identifier: Self::IDENTIFIER,
1802 ty: scale_info::meta_type::<Self>(),
1803 implicit: scale_info::meta_type::<Self::AdditionalSigned>()
1804 }]
1805 }
1806
1807 fn validate_unsigned(
1814 _call: &Self::Call,
1815 _info: &DispatchInfoOf<Self::Call>,
1816 _len: usize,
1817 ) -> TransactionValidity {
1818 Ok(ValidTransaction::default())
1819 }
1820
1821 fn pre_dispatch_unsigned(
1830 call: &Self::Call,
1831 info: &DispatchInfoOf<Self::Call>,
1832 len: usize,
1833 ) -> Result<(), TransactionValidityError> {
1834 Self::validate_unsigned(call, info, len).map(|_| ()).map_err(Into::into)
1835 }
1836}
1837
1838pub trait Applyable: Sized + Send + Sync {
1854 type Call: Dispatchable;
1856
1857 #[allow(deprecated)]
1862 fn validate<V: ValidateUnsigned<Call = Self::Call>>(
1863 &self,
1864 source: TransactionSource,
1865 info: &DispatchInfoOf<Self::Call>,
1866 len: usize,
1867 ) -> TransactionValidity;
1868
1869 #[allow(deprecated)]
1875 fn apply<V: ValidateUnsigned<Call = Self::Call>>(
1876 self,
1877 info: &DispatchInfoOf<Self::Call>,
1878 len: usize,
1879 ) -> crate::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Self::Call>>;
1880}
1881
1882pub trait GetRuntimeBlockType {
1884 type RuntimeBlock: self::Block;
1886}
1887
1888pub trait GetNodeBlockType {
1890 type NodeBlock: self::Block;
1892}
1893
1894#[deprecated(
1909 note = "`ValidateUnsigned` will be removed after April 2027. Use `#[pallet::authorize]` with `frame_system::AuthorizeCall` instead. See https://github.com/paritytech/polkadot-sdk/issues/2415"
1910)]
1911pub trait ValidateUnsigned {
1912 type Call;
1914
1915 fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> {
1928 Self::validate_unsigned(TransactionSource::InBlock, call)
1929 .map(|_| ())
1930 .map_err(Into::into)
1931 }
1932
1933 fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity;
1946}
1947
1948pub trait OpaqueKeys: Clone {
1951 type KeyTypeIdProviders;
1955
1956 fn key_ids() -> &'static [KeyTypeId];
1958
1959 fn get_raw(&self, i: KeyTypeId) -> &[u8];
1961
1962 fn get<T: Decode>(&self, i: KeyTypeId) -> Option<T> {
1964 T::decode(&mut self.get_raw(i)).ok()
1965 }
1966
1967 #[must_use]
1969 fn ownership_proof_is_valid(&self, owner: &[u8], proof: &[u8]) -> bool;
1970}
1971
1972pub struct AppendZerosInput<'a, T>(&'a mut T);
1977
1978impl<'a, T> AppendZerosInput<'a, T> {
1979 pub fn new(input: &'a mut T) -> Self {
1981 Self(input)
1982 }
1983}
1984
1985impl<'a, T: codec::Input> codec::Input for AppendZerosInput<'a, T> {
1986 fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
1987 Ok(None)
1988 }
1989
1990 fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
1991 let remaining = self.0.remaining_len()?;
1992 let completed = if let Some(n) = remaining {
1993 let readable = into.len().min(n);
1994 self.0.read(&mut into[..readable])?;
1996 readable
1997 } else {
1998 let mut i = 0;
2000 while i < into.len() {
2001 if let Ok(b) = self.0.read_byte() {
2002 into[i] = b;
2003 i += 1;
2004 } else {
2005 break;
2006 }
2007 }
2008 i
2009 };
2010 for i in &mut into[completed..] {
2012 *i = 0;
2013 }
2014 Ok(())
2015 }
2016}
2017
2018pub struct TrailingZeroInput<'a>(&'a [u8]);
2020
2021impl<'a> TrailingZeroInput<'a> {
2022 pub fn new(data: &'a [u8]) -> Self {
2024 Self(data)
2025 }
2026
2027 pub fn zeroes() -> Self {
2029 Self::new(&[][..])
2030 }
2031}
2032
2033impl<'a> codec::Input for TrailingZeroInput<'a> {
2034 fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
2035 Ok(None)
2036 }
2037
2038 fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
2039 let len_from_inner = into.len().min(self.0.len());
2040 into[..len_from_inner].copy_from_slice(&self.0[..len_from_inner]);
2041 for i in &mut into[len_from_inner..] {
2042 *i = 0;
2043 }
2044 self.0 = &self.0[len_from_inner..];
2045
2046 Ok(())
2047 }
2048}
2049
2050pub trait AccountIdConversion<AccountId>: Sized {
2052 fn into_account_truncating(&self) -> AccountId {
2055 self.into_sub_account_truncating(&())
2056 }
2057
2058 fn try_into_account(&self) -> Option<AccountId> {
2061 self.try_into_sub_account(&())
2062 }
2063
2064 fn try_from_account(a: &AccountId) -> Option<Self> {
2066 Self::try_from_sub_account::<()>(a).map(|x| x.0)
2067 }
2068
2069 fn into_sub_account_truncating<S: Encode>(&self, sub: S) -> AccountId;
2083
2084 fn try_into_sub_account<S: Encode>(&self, sub: S) -> Option<AccountId>;
2088
2089 fn try_from_sub_account<S: Decode>(x: &AccountId) -> Option<(Self, S)>;
2091}
2092
2093impl<T: Encode + Decode, Id: Encode + Decode + TypeId> AccountIdConversion<T> for Id {
2096 fn into_sub_account_truncating<S: Encode>(&self, sub: S) -> T {
2100 (Id::TYPE_ID, self, sub)
2101 .using_encoded(|b| T::decode(&mut TrailingZeroInput(b)))
2102 .expect("All byte sequences are valid `AccountIds`; qed")
2103 }
2104
2105 fn try_into_sub_account<S: Encode>(&self, sub: S) -> Option<T> {
2107 let encoded_seed = (Id::TYPE_ID, self, sub).encode();
2108 let account = T::decode(&mut TrailingZeroInput(&encoded_seed))
2109 .expect("All byte sequences are valid `AccountIds`; qed");
2110 if encoded_seed.len() <= account.encoded_size() {
2113 Some(account)
2114 } else {
2115 None
2116 }
2117 }
2118
2119 fn try_from_sub_account<S: Decode>(x: &T) -> Option<(Self, S)> {
2120 x.using_encoded(|d| {
2121 if d[0..4] != Id::TYPE_ID {
2122 return None;
2123 }
2124 let mut cursor = &d[4..];
2125 let result = Decode::decode(&mut cursor).ok()?;
2126 if cursor.iter().all(|x| *x == 0) {
2127 Some(result)
2128 } else {
2129 None
2130 }
2131 })
2132 }
2133}
2134
2135#[macro_export]
2142macro_rules! count {
2143 ($f:ident ($($x:tt)*) ) => ();
2144 ($f:ident ($($x:tt)*) $x1:tt) => { $f!($($x)* 0); };
2145 ($f:ident ($($x:tt)*) $x1:tt, $x2:tt) => { $f!($($x)* 0); $f!($($x)* 1); };
2146 ($f:ident ($($x:tt)*) $x1:tt, $x2:tt, $x3:tt) => { $f!($($x)* 0); $f!($($x)* 1); $f!($($x)* 2); };
2147 ($f:ident ($($x:tt)*) $x1:tt, $x2:tt, $x3:tt, $x4:tt) => {
2148 $f!($($x)* 0); $f!($($x)* 1); $f!($($x)* 2); $f!($($x)* 3);
2149 };
2150 ($f:ident ($($x:tt)*) $x1:tt, $x2:tt, $x3:tt, $x4:tt, $x5:tt) => {
2151 $f!($($x)* 0); $f!($($x)* 1); $f!($($x)* 2); $f!($($x)* 3); $f!($($x)* 4);
2152 };
2153}
2154
2155#[doc(hidden)]
2156#[macro_export]
2157macro_rules! impl_opaque_keys_inner {
2158 (
2159 $( #[ $attr:meta ] )*
2160 pub struct $name:ident {
2161 $(
2162 $( #[ $inner_attr:meta ] )*
2163 pub $field:ident: $type:ty,
2164 )*
2165 },
2166 $crate_path:path,
2167 ) => {
2168 $( #[ $attr ] )*
2169 #[doc = concat!("Generated by [`impl_opaque_keys!`](", stringify!($crate_path),"::impl_opaque_keys).")]
2171 #[derive(
2172 Clone, PartialEq, Eq,
2173 $crate::codec::Encode,
2174 $crate::codec::Decode,
2175 $crate::codec::DecodeWithMemTracking,
2176 $crate::scale_info::TypeInfo,
2177 Debug,
2178 )]
2179 pub struct $name {
2180 $(
2181 $( #[ $inner_attr ] )*
2182 pub $field: <$type as $crate::BoundToRuntimeAppPublic>::Public,
2183 )*
2184 }
2185
2186 impl $name {
2187 #[allow(dead_code)]
2200 pub fn generate(
2201 owner: &[u8],
2202 seed: Option<$crate::sp_std::vec::Vec<u8>>,
2203 ) -> $crate::traits::GeneratedSessionKeys<
2204 Self,
2205 (
2206 $(
2207 <
2208 <$type as $crate::BoundToRuntimeAppPublic>::Public
2209 as $crate::RuntimeAppPublic
2210 >::ProofOfPossession
2211 ),*
2212 )
2213 > {
2214 let mut keys = Self {
2215 $(
2216 $field: <
2217 <
2218 $type as $crate::BoundToRuntimeAppPublic
2219 >::Public as $crate::RuntimeAppPublic
2220 >::generate_pair(seed.clone()),
2221 )*
2222 };
2223
2224 let proof = keys.create_ownership_proof(owner)
2225 .expect("Private key that was generated a moment ago, should exist; qed");
2226
2227 $crate::traits::GeneratedSessionKeys {
2228 keys,
2229 proof
2230 }
2231 }
2232
2233 #[allow(dead_code)]
2235 pub fn into_raw_public_keys(
2236 self,
2237 ) -> $crate::Vec<($crate::Vec<u8>, $crate::KeyTypeId)> {
2238 let mut keys = Vec::new();
2239 $(
2240 keys.push((
2241 $crate::RuntimeAppPublic::to_raw_vec(&self.$field),
2242 <
2243 <
2244 $type as $crate::BoundToRuntimeAppPublic
2245 >::Public as $crate::RuntimeAppPublic
2246 >::ID,
2247 ));
2248 )*
2249
2250 keys
2251 }
2252
2253 #[allow(dead_code)]
2258 pub fn decode_into_raw_public_keys(
2259 encoded: &[u8],
2260 ) -> Option<$crate::Vec<($crate::Vec<u8>, $crate::KeyTypeId)>> {
2261 <Self as $crate::codec::Decode>::decode(&mut &encoded[..])
2262 .ok()
2263 .map(|s| s.into_raw_public_keys())
2264 }
2265
2266 #[allow(dead_code)]
2276 pub fn create_ownership_proof(
2277 &mut self,
2278 owner: &[u8],
2279 ) -> $crate::sp_std::result::Result<
2280 (
2281 $(
2282 <
2283 <$type as $crate::BoundToRuntimeAppPublic>::Public
2284 as $crate::RuntimeAppPublic
2285 >::ProofOfPossession
2286 ),*
2287 ),
2288 ()
2289 > {
2290 let res = ($(
2291 $crate::RuntimeAppPublic::generate_proof_of_possession(&mut self.$field, &owner).ok_or(())?
2292 ),*);
2293
2294 Ok(res)
2295 }
2296 }
2297
2298 impl $crate::traits::OpaqueKeys for $name {
2299 type KeyTypeIdProviders = ( $( $type, )* );
2300
2301 fn key_ids() -> &'static [$crate::KeyTypeId] {
2302 &[
2303 $(
2304 <
2305 <
2306 $type as $crate::BoundToRuntimeAppPublic
2307 >::Public as $crate::RuntimeAppPublic
2308 >::ID
2309 ),*
2310 ]
2311 }
2312
2313 fn get_raw(&self, i: $crate::KeyTypeId) -> &[u8] {
2314 match i {
2315 $(
2316 i if i == <
2317 <
2318 $type as $crate::BoundToRuntimeAppPublic
2319 >::Public as $crate::RuntimeAppPublic
2320 >::ID =>
2321 self.$field.as_ref(),
2322 )*
2323 _ => &[],
2324 }
2325 }
2326
2327 fn ownership_proof_is_valid(&self, owner: &[u8], proof: &[u8]) -> bool {
2328 let Ok(proof) = <($(
2330 <
2331 <
2332 $type as $crate::BoundToRuntimeAppPublic
2333 >::Public as $crate::RuntimeAppPublic
2334 >::ProofOfPossession
2335 ),*) as $crate::codec::DecodeAll>::decode_all(&mut &proof[..]) else {
2336 return false
2337 };
2338
2339 let ( $( $field ),* ) = proof;
2341
2342 $(
2344 let valid = $crate::RuntimeAppPublic::verify_proof_of_possession(&self.$field, &owner, &$field);
2345
2346 if !valid {
2347 return false
2349 }
2350 )*
2351
2352 true
2353 }
2354 }
2355 };
2356}
2357
2358#[derive(Debug, Clone, Encode, Decode, TypeInfo)]
2365pub struct GeneratedSessionKeys<Keys, Proof> {
2366 pub keys: Keys,
2368 pub proof: Proof,
2370}
2371
2372#[macro_export]
2402#[cfg(any(feature = "serde", feature = "std"))]
2403macro_rules! impl_opaque_keys {
2404 {
2405 $( #[ $attr:meta ] )*
2406 pub struct $name:ident {
2407 $(
2408 $( #[ $inner_attr:meta ] )*
2409 pub $field:ident: $type:ty,
2410 )*
2411 }
2412 } => {
2413 $crate::paste::paste! {
2414 use $crate::serde as [< __opaque_keys_serde_import__ $name >];
2415
2416 $crate::impl_opaque_keys_inner! {
2417 $( #[ $attr ] )*
2418 #[derive($crate::serde::Serialize, $crate::serde::Deserialize)]
2419 #[serde(crate = "__opaque_keys_serde_import__" $name)]
2420 pub struct $name {
2421 $(
2422 $( #[ $inner_attr ] )*
2423 pub $field: $type,
2424 )*
2425 },
2426 $crate,
2427 }
2428 }
2429 }
2430}
2431
2432#[macro_export]
2433#[cfg(all(not(feature = "std"), not(feature = "serde")))]
2434#[doc(hidden)]
2435macro_rules! impl_opaque_keys {
2436 {
2437 $( #[ $attr:meta ] )*
2438 pub struct $name:ident {
2439 $(
2440 $( #[ $inner_attr:meta ] )*
2441 pub $field:ident: $type:ty,
2442 )*
2443 }
2444 } => {
2445 $crate::impl_opaque_keys_inner! {
2446 $( #[ $attr ] )*
2447 pub struct $name {
2448 $(
2449 $( #[ $inner_attr ] )*
2450 pub $field: $type,
2451 )*
2452 },
2453 $crate,
2454 }
2455 }
2456}
2457
2458#[cfg(feature = "std")]
2460pub trait BlockIdTo<Block: self::Block> {
2461 type Error: std::error::Error;
2463
2464 fn to_hash(
2466 &self,
2467 block_id: &crate::generic::BlockId<Block>,
2468 ) -> Result<Option<Block::Hash>, Self::Error>;
2469
2470 fn to_number(
2472 &self,
2473 block_id: &crate::generic::BlockId<Block>,
2474 ) -> Result<Option<NumberFor<Block>>, Self::Error>;
2475}
2476
2477pub trait BlockNumberProvider {
2479 type BlockNumber: Codec
2481 + DecodeWithMemTracking
2482 + Clone
2483 + Ord
2484 + Eq
2485 + AtLeast32BitUnsigned
2486 + TypeInfo
2487 + Debug
2488 + MaxEncodedLen
2489 + Copy
2490 + EncodeLike
2491 + Default;
2492
2493 fn current_block_number() -> Self::BlockNumber;
2509
2510 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
2516 fn set_block_number(_block: Self::BlockNumber) {}
2517}
2518
2519impl BlockNumberProvider for () {
2520 type BlockNumber = u32;
2521 fn current_block_number() -> Self::BlockNumber {
2522 0
2523 }
2524}
2525
2526#[cfg(test)]
2527mod tests {
2528 use super::*;
2529 use crate::codec::{Decode, Encode, Input};
2530 #[cfg(feature = "bls-experimental")]
2531 use sp_core::ecdsa_bls381;
2532 use sp_core::{
2533 crypto::{Pair, UncheckedFrom},
2534 ecdsa, ed25519,
2535 proof_of_possession::ProofOfPossessionGenerator,
2536 sr25519,
2537 };
2538 use std::sync::Arc;
2539
2540 macro_rules! signature_verify_test {
2541 ($algorithm:ident) => {
2542 let msg = &b"test-message"[..];
2543 let wrong_msg = &b"test-msg"[..];
2544 let (pair, _) = $algorithm::Pair::generate();
2545
2546 let signature = pair.sign(&msg);
2547 assert!($algorithm::Pair::verify(&signature, msg, &pair.public()));
2548
2549 assert!(signature.verify(msg, &pair.public()));
2550 assert!(!signature.verify(wrong_msg, &pair.public()));
2551 };
2552 }
2553
2554 mod t {
2555 use sp_application_crypto::{app_crypto, sr25519};
2556 use sp_core::crypto::KeyTypeId;
2557 app_crypto!(sr25519, KeyTypeId(*b"test"));
2558 }
2559
2560 #[test]
2561 fn app_verify_works() {
2562 use super::AppVerify;
2563 use t::*;
2564
2565 let s = Signature::try_from(vec![0; 64]).unwrap();
2566 let _ = s.verify(&[0u8; 100][..], &Public::unchecked_from([0; 32]));
2567 }
2568
2569 #[derive(Encode, Decode, Default, PartialEq, Debug)]
2570 struct U128Value(u128);
2571 impl super::TypeId for U128Value {
2572 const TYPE_ID: [u8; 4] = [0x0d, 0xf0, 0x0d, 0xf0];
2573 }
2574 #[derive(Encode, Decode, Default, PartialEq, Debug)]
2577 struct U32Value(u32);
2578 impl super::TypeId for U32Value {
2579 const TYPE_ID: [u8; 4] = [0x0d, 0xf0, 0xfe, 0xca];
2580 }
2581 #[derive(Encode, Decode, Default, PartialEq, Debug)]
2584 struct U16Value(u16);
2585 impl super::TypeId for U16Value {
2586 const TYPE_ID: [u8; 4] = [0xfe, 0xca, 0x0d, 0xf0];
2587 }
2588 type AccountId = u64;
2591
2592 #[test]
2593 fn into_account_truncating_should_work() {
2594 let r: AccountId = U32Value::into_account_truncating(&U32Value(0xdeadbeef));
2595 assert_eq!(r, 0x_deadbeef_cafef00d);
2596 }
2597
2598 #[test]
2599 fn try_into_account_should_work() {
2600 let r: AccountId = U32Value::try_into_account(&U32Value(0xdeadbeef)).unwrap();
2601 assert_eq!(r, 0x_deadbeef_cafef00d);
2602
2603 let maybe: Option<AccountId> = U128Value::try_into_account(&U128Value(u128::MAX));
2605 assert!(maybe.is_none());
2606 }
2607
2608 #[test]
2609 fn try_from_account_should_work() {
2610 let r = U32Value::try_from_account(&0x_deadbeef_cafef00d_u64);
2611 assert_eq!(r.unwrap(), U32Value(0xdeadbeef));
2612 }
2613
2614 #[test]
2615 fn into_account_truncating_with_fill_should_work() {
2616 let r: AccountId = U16Value::into_account_truncating(&U16Value(0xc0da));
2617 assert_eq!(r, 0x_0000_c0da_f00dcafe);
2618 }
2619
2620 #[test]
2621 fn try_into_sub_account_should_work() {
2622 let r: AccountId = U16Value::try_into_account(&U16Value(0xc0da)).unwrap();
2623 assert_eq!(r, 0x_0000_c0da_f00dcafe);
2624
2625 let maybe: Option<AccountId> = U16Value::try_into_sub_account(
2626 &U16Value(0xc0da),
2627 "a really large amount of additional encoded information which will certainly overflow the account id type ;)"
2628 );
2629
2630 assert!(maybe.is_none())
2631 }
2632
2633 #[test]
2634 fn try_from_account_with_fill_should_work() {
2635 let r = U16Value::try_from_account(&0x0000_c0da_f00dcafe_u64);
2636 assert_eq!(r.unwrap(), U16Value(0xc0da));
2637 }
2638
2639 #[test]
2640 fn bad_try_from_account_should_fail() {
2641 let r = U16Value::try_from_account(&0x0000_c0de_baadcafe_u64);
2642 assert!(r.is_none());
2643 let r = U16Value::try_from_account(&0x0100_c0da_f00dcafe_u64);
2644 assert!(r.is_none());
2645 }
2646
2647 #[test]
2648 fn trailing_zero_should_work() {
2649 let mut t = super::TrailingZeroInput(&[1, 2, 3]);
2650 assert_eq!(t.remaining_len(), Ok(None));
2651 let mut buffer = [0u8; 2];
2652 assert_eq!(t.read(&mut buffer), Ok(()));
2653 assert_eq!(t.remaining_len(), Ok(None));
2654 assert_eq!(buffer, [1, 2]);
2655 assert_eq!(t.read(&mut buffer), Ok(()));
2656 assert_eq!(t.remaining_len(), Ok(None));
2657 assert_eq!(buffer, [3, 0]);
2658 assert_eq!(t.read(&mut buffer), Ok(()));
2659 assert_eq!(t.remaining_len(), Ok(None));
2660 assert_eq!(buffer, [0, 0]);
2661 }
2662
2663 #[test]
2664 fn ed25519_verify_works() {
2665 signature_verify_test!(ed25519);
2666 }
2667
2668 #[test]
2669 fn sr25519_verify_works() {
2670 signature_verify_test!(sr25519);
2671 }
2672
2673 #[test]
2674 fn ecdsa_verify_works() {
2675 signature_verify_test!(ecdsa);
2676
2677 let msg = &b"test-message"[..];
2678 let (pair, _) = ecdsa::Pair::generate();
2679 let signature = pair.sign(msg);
2680 let high_s_signature =
2681 ecdsa::Signature::from_raw(crate::tests::make_high_s_signature(signature.as_ref()));
2682 assert!(!high_s_signature.verify(msg, &pair.public()));
2683 }
2684
2685 #[test]
2686 #[cfg(feature = "bls-experimental")]
2687 fn ecdsa_bls381_verify_works() {
2688 signature_verify_test!(ecdsa_bls381);
2689 }
2690
2691 pub struct Sr25519Key;
2692 impl crate::BoundToRuntimeAppPublic for Sr25519Key {
2693 type Public = sp_application_crypto::sr25519::AppPublic;
2694 }
2695
2696 pub struct Ed25519Key;
2697 impl crate::BoundToRuntimeAppPublic for Ed25519Key {
2698 type Public = sp_application_crypto::ed25519::AppPublic;
2699 }
2700
2701 pub struct EcdsaKey;
2702 impl crate::BoundToRuntimeAppPublic for EcdsaKey {
2703 type Public = sp_application_crypto::ecdsa::AppPublic;
2704 }
2705
2706 impl_opaque_keys! {
2707 pub struct SessionKeys {
2709 pub sr25519: Sr25519Key,
2710 pub ed25519: Ed25519Key,
2711 pub ecdsa: EcdsaKey,
2712 }
2713 }
2714
2715 #[test]
2716 fn opaque_keys_ownership_proof_works() {
2717 let mut sr25519 = sp_core::sr25519::Pair::generate().0;
2718 let mut ed25519 = sp_core::ed25519::Pair::generate().0;
2719 let mut ecdsa = sp_core::ecdsa::Pair::generate().0;
2720
2721 let session_keys = SessionKeys {
2722 sr25519: sr25519.public().into(),
2723 ed25519: ed25519.public().into(),
2724 ecdsa: ecdsa.public().into(),
2725 };
2726
2727 let owner = &b"owner"[..];
2728
2729 let sr25519_sig = sr25519.generate_proof_of_possession(&owner);
2730 let ed25519_sig = ed25519.generate_proof_of_possession(&owner);
2731 let ecdsa_sig = ecdsa.generate_proof_of_possession(&owner);
2732
2733 for invalidate in [None, Some(0), Some(1), Some(2)] {
2734 let proof = if let Some(invalidate) = invalidate {
2735 match invalidate {
2736 0 => (
2737 sr25519.generate_proof_of_possession(&b"invalid"[..]),
2738 &ed25519_sig,
2739 &ecdsa_sig,
2740 )
2741 .encode(),
2742 1 => (
2743 &sr25519_sig,
2744 ed25519.generate_proof_of_possession(&b"invalid"[..]),
2745 &ecdsa_sig,
2746 )
2747 .encode(),
2748 2 => (
2749 &sr25519_sig,
2750 &ed25519_sig,
2751 ecdsa.generate_proof_of_possession(&b"invalid"[..]),
2752 )
2753 .encode(),
2754 _ => unreachable!(),
2755 }
2756 } else {
2757 (&sr25519_sig, &ed25519_sig, &ecdsa_sig).encode()
2758 };
2759
2760 assert_eq!(session_keys.ownership_proof_is_valid(owner, &proof), invalidate.is_none());
2761 }
2762
2763 let proof = (&sr25519_sig, &ed25519_sig, &ecdsa_sig, "hello").encode();
2765 assert!(!session_keys.ownership_proof_is_valid(owner, &proof));
2766
2767 let mut ext = sp_io::TestExternalities::default();
2768 ext.register_extension(sp_keystore::KeystoreExt(Arc::new(
2769 sp_keystore::testing::MemoryKeystore::new(),
2770 )));
2771
2772 ext.execute_with(|| {
2773 let session_keys = SessionKeys::generate(&owner, None);
2774
2775 assert!(session_keys
2776 .keys
2777 .ownership_proof_is_valid(&owner, &session_keys.proof.encode()));
2778 });
2779 }
2780}