mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-07 04:58:01 +00:00
e63730b763
* Convert another instance of Into impl to From in the macros * Convert another location
570 lines
15 KiB
Rust
570 lines
15 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Macros that define an Origin type. Every function call to your runtime has an origin which
|
|
//! specifies where the extrinsic was generated from.
|
|
|
|
/// Constructs an Origin type for a runtime. This is usually called automatically by the
|
|
/// construct_runtime macro. See also __create_decl_macro.
|
|
#[macro_export]
|
|
macro_rules! impl_outer_origin {
|
|
|
|
// Macro transformations (to convert invocations with incomplete parameters to the canonical
|
|
// form)
|
|
(
|
|
$(#[$attr:meta])*
|
|
pub enum $name:ident for $runtime:ident {
|
|
$( $rest_without_system:tt )*
|
|
}
|
|
) => {
|
|
$crate::impl_outer_origin! {
|
|
$(#[$attr])*
|
|
pub enum $name for $runtime where system = frame_system {
|
|
$( $rest_without_system )*
|
|
}
|
|
}
|
|
};
|
|
|
|
(
|
|
$(#[$attr:meta])*
|
|
pub enum $name:ident for $runtime:ident where
|
|
system = $system:ident
|
|
$(, system_index = $system_index:tt)?
|
|
{
|
|
$( $rest_with_system:tt )*
|
|
}
|
|
) => {
|
|
$crate::paste::item! {
|
|
$crate::impl_outer_origin!(
|
|
$( #[$attr] )*;
|
|
$name;
|
|
[< $name Caller >];
|
|
$runtime;
|
|
$system;
|
|
system_index { $( $system_index )? };
|
|
Modules { $( $rest_with_system )* };
|
|
);
|
|
}
|
|
};
|
|
|
|
// Generic + Instance
|
|
(
|
|
$(#[$attr:meta])*;
|
|
$name:ident;
|
|
$caller_name:ident;
|
|
$runtime:ident;
|
|
$system:ident;
|
|
system_index { $( $system_index:tt )? };
|
|
Modules {
|
|
$( #[codec(index = $index:tt)] )? $module:ident $instance:ident <T>
|
|
$(, $( $rest_module:tt )* )?
|
|
};
|
|
$( $parsed:tt )*
|
|
) => {
|
|
$crate::impl_outer_origin!(
|
|
$( #[$attr] )*;
|
|
$name;
|
|
$caller_name;
|
|
$runtime;
|
|
$system;
|
|
system_index { $( $system_index )? };
|
|
Modules { $( $( $rest_module )* )? };
|
|
$( $parsed )* $module <$runtime> { $instance } index { $( $index )? },
|
|
);
|
|
};
|
|
|
|
// Instance
|
|
(
|
|
$(#[$attr:meta])*;
|
|
$name:ident;
|
|
$caller_name:ident;
|
|
$runtime:ident;
|
|
$system:ident;
|
|
system_index { $( $system_index:tt )? };
|
|
Modules {
|
|
$( #[codec(index = $index:tt )] )? $module:ident $instance:ident
|
|
$(, $rest_module:tt )*
|
|
};
|
|
$( $parsed:tt )*
|
|
) => {
|
|
$crate::impl_outer_origin!(
|
|
$( #[$attr] )*;
|
|
$name;
|
|
$caller_name;
|
|
$runtime;
|
|
$system;
|
|
system_index { $( $system_index )? };
|
|
Modules { $( $rest_module )* };
|
|
$( $parsed )* $module { $instance } index { $( $index )? },
|
|
);
|
|
};
|
|
|
|
// Generic
|
|
(
|
|
$(#[$attr:meta])*;
|
|
$name:ident;
|
|
$caller_name:ident;
|
|
$runtime:ident;
|
|
$system:ident;
|
|
system_index { $( $system_index:tt )? };
|
|
Modules {
|
|
$( #[codec(index = $index:tt )] )? $module:ident <T>
|
|
$(, $( $rest_module:tt )* )?
|
|
};
|
|
$( $parsed:tt )*
|
|
) => {
|
|
$crate::impl_outer_origin!(
|
|
$( #[$attr] )*;
|
|
$name;
|
|
$caller_name;
|
|
$runtime;
|
|
$system;
|
|
system_index { $( $system_index )? };
|
|
Modules { $( $( $rest_module )* )? };
|
|
$( $parsed )* $module <$runtime> index { $( $index )? },
|
|
);
|
|
};
|
|
|
|
// No Generic and no Instance
|
|
(
|
|
$(#[$attr:meta])*;
|
|
$name:ident;
|
|
$caller_name:ident;
|
|
$runtime:ident;
|
|
$system:ident;
|
|
system_index { $( $system_index:tt )? };
|
|
Modules {
|
|
$( #[codec(index = $index:tt )] )? $module:ident
|
|
$(, $( $rest_module:tt )* )?
|
|
};
|
|
$( $parsed:tt )*
|
|
) => {
|
|
$crate::impl_outer_origin!(
|
|
$( #[$attr] )*;
|
|
$name;
|
|
$caller_name;
|
|
$runtime;
|
|
$system;
|
|
system_index { $( $system_index )? };
|
|
Modules { $( $( $rest_module )* )? };
|
|
$( $parsed )* $module index { $( $index )? },
|
|
);
|
|
};
|
|
|
|
// The main macro expansion that actually renders the Origin enum code.
|
|
(
|
|
$(#[$attr:meta])*;
|
|
$name:ident;
|
|
$caller_name:ident;
|
|
$runtime:ident;
|
|
$system:ident;
|
|
system_index { $( $system_index:tt )? };
|
|
Modules { };
|
|
$(
|
|
$module:ident
|
|
$( < $generic:ident > )?
|
|
$( { $generic_instance:ident } )?
|
|
index { $( $index:tt )? },
|
|
)*
|
|
) => {
|
|
// WARNING: All instance must hold the filter `frame_system::Config::BaseCallFilter`, except
|
|
// when caller is system Root. One can use `OriginTrait::reset_filter` to do so.
|
|
#[derive(Clone)]
|
|
pub struct $name {
|
|
caller: $caller_name,
|
|
filter: $crate::sp_std::rc::Rc<Box<dyn Fn(&<$runtime as $system::Config>::Call) -> bool>>,
|
|
}
|
|
|
|
#[cfg(not(feature = "std"))]
|
|
impl $crate::sp_std::fmt::Debug for $name {
|
|
fn fmt(
|
|
&self,
|
|
fmt: &mut $crate::sp_std::fmt::Formatter
|
|
) -> $crate::sp_std::result::Result<(), $crate::sp_std::fmt::Error> {
|
|
fmt.write_str("<wasm:stripped>")
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "std")]
|
|
impl $crate::sp_std::fmt::Debug for $name {
|
|
fn fmt(
|
|
&self,
|
|
fmt: &mut $crate::sp_std::fmt::Formatter
|
|
) -> $crate::sp_std::result::Result<(), $crate::sp_std::fmt::Error> {
|
|
fmt.debug_struct(stringify!($name))
|
|
.field("caller", &self.caller)
|
|
.field("filter", &"[function ptr]")
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl $crate::traits::OriginTrait for $name {
|
|
type Call = <$runtime as $system::Config>::Call;
|
|
type PalletsOrigin = $caller_name;
|
|
type AccountId = <$runtime as $system::Config>::AccountId;
|
|
|
|
fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) {
|
|
let f = self.filter.clone();
|
|
|
|
self.filter = $crate::sp_std::rc::Rc::new(Box::new(move |call| {
|
|
f(call) && filter(call)
|
|
}));
|
|
}
|
|
|
|
fn reset_filter(&mut self) {
|
|
let filter = <
|
|
<$runtime as $system::Config>::BaseCallFilter
|
|
as $crate::traits::Filter<<$runtime as $system::Config>::Call>
|
|
>::filter;
|
|
|
|
self.filter = $crate::sp_std::rc::Rc::new(Box::new(filter));
|
|
}
|
|
|
|
fn set_caller_from(&mut self, other: impl Into<Self>) {
|
|
self.caller = other.into().caller
|
|
}
|
|
|
|
fn filter_call(&self, call: &Self::Call) -> bool {
|
|
(self.filter)(call)
|
|
}
|
|
|
|
fn caller(&self) -> &Self::PalletsOrigin {
|
|
&self.caller
|
|
}
|
|
|
|
fn try_with_caller<R>(
|
|
mut self,
|
|
f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
|
|
) -> Result<R, Self> {
|
|
match f(self.caller) {
|
|
Ok(r) => Ok(r),
|
|
Err(caller) => { self.caller = caller; Err(self) }
|
|
}
|
|
}
|
|
|
|
/// Create with system none origin and `frame-system::Config::BaseCallFilter`.
|
|
fn none() -> Self {
|
|
$system::RawOrigin::None.into()
|
|
}
|
|
/// Create with system root origin and no filter.
|
|
fn root() -> Self {
|
|
$system::RawOrigin::Root.into()
|
|
}
|
|
/// Create with system signed origin and `frame-system::Config::BaseCallFilter`.
|
|
fn signed(by: <$runtime as $system::Config>::AccountId) -> Self {
|
|
$system::RawOrigin::Signed(by).into()
|
|
}
|
|
}
|
|
|
|
$crate::paste::item! {
|
|
#[derive(Clone, PartialEq, Eq, $crate::RuntimeDebug, $crate::codec::Encode, $crate::codec::Decode)]
|
|
$(#[$attr])*
|
|
#[allow(non_camel_case_types)]
|
|
pub enum $caller_name {
|
|
$( #[codec(index = $system_index)] )?
|
|
system($system::Origin<$runtime>),
|
|
$(
|
|
$( #[codec(index = $index)] )?
|
|
[< $module $( _ $generic_instance )? >]
|
|
($module::Origin < $( $generic, )? $( $module::$generic_instance )? > ),
|
|
)*
|
|
#[allow(dead_code)]
|
|
Void($crate::Void)
|
|
}
|
|
}
|
|
|
|
// For backwards compatibility and ease of accessing these functions.
|
|
#[allow(dead_code)]
|
|
impl $name {
|
|
/// Create with system none origin and `frame-system::Config::BaseCallFilter`.
|
|
pub fn none() -> Self {
|
|
<$name as $crate::traits::OriginTrait>::none()
|
|
}
|
|
/// Create with system root origin and no filter.
|
|
pub fn root() -> Self {
|
|
<$name as $crate::traits::OriginTrait>::root()
|
|
}
|
|
/// Create with system signed origin and `frame-system::Config::BaseCallFilter`.
|
|
pub fn signed(by: <$runtime as $system::Config>::AccountId) -> Self {
|
|
<$name as $crate::traits::OriginTrait>::signed(by)
|
|
}
|
|
}
|
|
|
|
impl From<$system::Origin<$runtime>> for $caller_name {
|
|
fn from(x: $system::Origin<$runtime>) -> Self {
|
|
$caller_name::system(x)
|
|
}
|
|
}
|
|
|
|
impl $crate::sp_std::convert::TryFrom<$caller_name> for $system::Origin<$runtime> {
|
|
type Error = $caller_name;
|
|
fn try_from(x: $caller_name)
|
|
-> $crate::sp_std::result::Result<$system::Origin<$runtime>, $caller_name>
|
|
{
|
|
if let $caller_name::system(l) = x {
|
|
Ok(l)
|
|
} else {
|
|
Err(x)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<$system::Origin<$runtime>> for $name {
|
|
/// Convert to runtime origin:
|
|
/// * root origin is built with no filter
|
|
/// * others use `frame-system::Config::BaseCallFilter`
|
|
fn from(x: $system::Origin<$runtime>) -> Self {
|
|
let o: $caller_name = x.into();
|
|
o.into()
|
|
}
|
|
}
|
|
|
|
impl From<$caller_name> for $name {
|
|
fn from(x: $caller_name) -> Self {
|
|
let mut o = $name {
|
|
caller: x,
|
|
filter: $crate::sp_std::rc::Rc::new(Box::new(|_| true)),
|
|
};
|
|
|
|
// Root has no filter
|
|
if !matches!(o.caller, $caller_name::system($system::Origin::<$runtime>::Root)) {
|
|
$crate::traits::OriginTrait::reset_filter(&mut o);
|
|
}
|
|
|
|
o
|
|
}
|
|
}
|
|
|
|
impl From<$name> for $crate::sp_std::result::Result<$system::Origin<$runtime>, $name>{
|
|
/// NOTE: converting to pallet origin loses the origin filter information.
|
|
fn from(val: $name) -> Self {
|
|
if let $caller_name::system(l) = val.caller {
|
|
Ok(l)
|
|
} else {
|
|
Err(val)
|
|
}
|
|
}
|
|
}
|
|
impl From<Option<<$runtime as $system::Config>::AccountId>> for $name {
|
|
/// Convert to runtime origin with caller being system signed or none and use filter
|
|
/// `frame-system::Config::BaseCallFilter`.
|
|
fn from(x: Option<<$runtime as $system::Config>::AccountId>) -> Self {
|
|
<$system::Origin<$runtime>>::from(x).into()
|
|
}
|
|
}
|
|
|
|
$(
|
|
$crate::paste::item! {
|
|
impl From<$module::Origin < $( $generic )? $(, $module::$generic_instance )? > > for $caller_name {
|
|
fn from(x: $module::Origin < $( $generic )? $(, $module::$generic_instance )? >) -> Self {
|
|
$caller_name::[< $module $( _ $generic_instance )? >](x)
|
|
}
|
|
}
|
|
|
|
impl From<$module::Origin < $( $generic )? $(, $module::$generic_instance )? > > for $name {
|
|
/// Convert to runtime origin using `frame-system::Config::BaseCallFilter`.
|
|
fn from(x: $module::Origin < $( $generic )? $(, $module::$generic_instance )? >) -> Self {
|
|
let x: $caller_name = x.into();
|
|
x.into()
|
|
}
|
|
}
|
|
impl From<$name> for $crate::sp_std::result::Result<
|
|
$module::Origin < $( $generic )? $(, $module::$generic_instance )? >,
|
|
$name,
|
|
>
|
|
{
|
|
/// NOTE: converting to pallet origin loses the origin filter information.
|
|
fn from(val: $name) -> Self {
|
|
if let $caller_name::[< $module $( _ $generic_instance )? >](l) = val.caller {
|
|
Ok(l)
|
|
} else {
|
|
Err(val)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl $crate::sp_std::convert::TryFrom<
|
|
$caller_name
|
|
> for $module::Origin < $( $generic )? $(, $module::$generic_instance )? > {
|
|
type Error = $caller_name;
|
|
fn try_from(x: $caller_name) -> $crate::sp_std::result::Result<
|
|
$module::Origin < $( $generic )? $(, $module::$generic_instance )? >,
|
|
$caller_name,
|
|
> {
|
|
if let $caller_name::[< $module $( _ $generic_instance )? >](l) = x {
|
|
Ok(l)
|
|
} else {
|
|
Err(x)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
)*
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use codec::{Encode, Decode};
|
|
use crate::traits::{Filter, OriginTrait};
|
|
mod frame_system {
|
|
use super::*;
|
|
|
|
pub trait Config {
|
|
type AccountId;
|
|
type Call;
|
|
type BaseCallFilter;
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
|
pub enum RawOrigin<AccountId> {
|
|
Root,
|
|
Signed(AccountId),
|
|
None,
|
|
}
|
|
|
|
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
|
|
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
|
|
match s {
|
|
Some(who) => RawOrigin::Signed(who),
|
|
None => RawOrigin::None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type Origin<T> = RawOrigin<<T as Config>::AccountId>;
|
|
}
|
|
|
|
mod origin_without_generic {
|
|
use super::*;
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
|
pub struct Origin;
|
|
}
|
|
|
|
mod origin_with_generic {
|
|
use super::*;
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
|
pub struct Origin<T> {
|
|
t: T
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
|
pub struct TestRuntime;
|
|
|
|
pub struct BaseCallFilter;
|
|
impl Filter<u32> for BaseCallFilter {
|
|
fn filter(c: &u32) -> bool {
|
|
*c % 2 == 0
|
|
}
|
|
}
|
|
|
|
impl frame_system::Config for TestRuntime {
|
|
type AccountId = u32;
|
|
type Call = u32;
|
|
type BaseCallFilter = BaseCallFilter;
|
|
}
|
|
|
|
impl_outer_origin!(
|
|
pub enum OriginWithoutSystem for TestRuntime {
|
|
origin_without_generic,
|
|
origin_with_generic<T>,
|
|
}
|
|
);
|
|
|
|
impl_outer_origin!(
|
|
pub enum OriginWithoutSystem2 for TestRuntime {
|
|
origin_with_generic<T>,
|
|
origin_without_generic
|
|
}
|
|
);
|
|
|
|
impl_outer_origin!(
|
|
pub enum OriginWithSystem for TestRuntime where system = frame_system {
|
|
origin_without_generic,
|
|
origin_with_generic<T>
|
|
}
|
|
);
|
|
|
|
impl_outer_origin!(
|
|
pub enum OriginWithSystem2 for TestRuntime where system = frame_system {
|
|
origin_with_generic<T>,
|
|
origin_without_generic,
|
|
}
|
|
);
|
|
|
|
impl_outer_origin!(
|
|
pub enum OriginEmpty for TestRuntime where system = frame_system {}
|
|
);
|
|
|
|
impl_outer_origin!(
|
|
pub enum OriginIndices for TestRuntime where system = frame_system, system_index = 11 {
|
|
origin_with_generic<T>,
|
|
#[codec(index = 10)] origin_without_generic,
|
|
}
|
|
);
|
|
|
|
#[test]
|
|
fn test_default_filter() {
|
|
assert_eq!(OriginWithSystem::root().filter_call(&0), true);
|
|
assert_eq!(OriginWithSystem::root().filter_call(&1), true);
|
|
assert_eq!(OriginWithSystem::none().filter_call(&0), true);
|
|
assert_eq!(OriginWithSystem::none().filter_call(&1), false);
|
|
assert_eq!(OriginWithSystem::signed(0).filter_call(&0), true);
|
|
assert_eq!(OriginWithSystem::signed(0).filter_call(&1), false);
|
|
assert_eq!(OriginWithSystem::from(Some(0)).filter_call(&0), true);
|
|
assert_eq!(OriginWithSystem::from(Some(0)).filter_call(&1), false);
|
|
assert_eq!(OriginWithSystem::from(None).filter_call(&0), true);
|
|
assert_eq!(OriginWithSystem::from(None).filter_call(&1), false);
|
|
assert_eq!(OriginWithSystem::from(origin_without_generic::Origin).filter_call(&0), true);
|
|
assert_eq!(OriginWithSystem::from(origin_without_generic::Origin).filter_call(&1), false);
|
|
|
|
let mut origin = OriginWithSystem::from(Some(0));
|
|
|
|
origin.add_filter(|c| *c % 2 == 1);
|
|
assert_eq!(origin.filter_call(&0), false);
|
|
assert_eq!(origin.filter_call(&1), false);
|
|
|
|
origin.set_caller_from(OriginWithSystem::root());
|
|
assert!(matches!(origin.caller, OriginWithSystemCaller::system(frame_system::RawOrigin::Root)));
|
|
assert_eq!(origin.filter_call(&0), false);
|
|
assert_eq!(origin.filter_call(&1), false);
|
|
|
|
origin.reset_filter();
|
|
assert_eq!(origin.filter_call(&0), true);
|
|
assert_eq!(origin.filter_call(&1), false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_codec() {
|
|
use codec::Encode;
|
|
assert_eq!(OriginIndices::root().caller.encode()[0], 11);
|
|
let without_generic_variant = OriginIndicesCaller::origin_without_generic(
|
|
origin_without_generic::Origin
|
|
);
|
|
assert_eq!(without_generic_variant.encode()[0], 10);
|
|
|
|
assert_eq!(OriginWithoutSystem::root().caller.encode()[0], 0);
|
|
let without_generic_variant = OriginWithoutSystemCaller::origin_without_generic(
|
|
origin_without_generic::Origin
|
|
);
|
|
assert_eq!(without_generic_variant.encode()[0], 1);
|
|
}
|
|
}
|