Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// This file is part of Substrate.

// Copyright (C) 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

use crate::construct_runtime::{parse::PalletPath, Pallet};
use proc_macro2::{Ident, TokenStream};
use quote::quote;

pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream {
let mut conversion_fns = Vec::new();
let mut hold_reason_variants = Vec::new();
for decl in pallet_decls {
if let Some(_) = decl.find_part("HoldReason") {
let variant_name = &decl.name;
let path = &decl.path;
let index = &decl.index;

conversion_fns.push(expand_conversion_fn(path, variant_name));

hold_reason_variants.push(quote! {
#[codec(index = #index)]
#variant_name(#path::HoldReason),
});
}
}

quote! {
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
#scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen,
#scrate::scale_info::TypeInfo,
#scrate::RuntimeDebug,
)]
pub enum RuntimeHoldReason {
#( #hold_reason_variants )*
}

#( #conversion_fns )*
}
}

fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream {
quote! {
impl From<#path::HoldReason> for RuntimeHoldReason {
fn from(hr: #path::HoldReason) -> Self {
RuntimeHoldReason::#variant_name(hr)
}
}
}
}
2 changes: 2 additions & 0 deletions frame/support/procedural/src/construct_runtime/expand/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
mod call;
mod config;
mod event;
mod hold_reason;
mod inherent;
mod metadata;
mod origin;
Expand All @@ -26,6 +27,7 @@ mod unsigned;
pub use call::expand_outer_dispatch;
pub use config::expand_outer_config;
pub use event::expand_outer_event;
pub use hold_reason::expand_outer_hold_reason;
pub use inherent::expand_outer_inherent;
pub use metadata::expand_runtime_metadata;
pub use origin::expand_outer_origin;
Expand Down
3 changes: 3 additions & 0 deletions frame/support/procedural/src/construct_runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ fn construct_runtime_final_expansion(
let inherent =
expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate);
let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate);
let hold_reason = expand::expand_outer_hold_reason(&pallets, &scrate);
let integrity_test = decl_integrity_test(&scrate);
let static_assertions = decl_static_assertions(&name, &pallets, &scrate);

Expand Down Expand Up @@ -307,6 +308,8 @@ fn construct_runtime_final_expansion(

#validate_unsigned

#hold_reason

#integrity_test

#static_assertions
Expand Down
6 changes: 6 additions & 0 deletions frame/support/procedural/src/construct_runtime/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ mod keyword {
syn::custom_keyword!(Origin);
syn::custom_keyword!(Inherent);
syn::custom_keyword!(ValidateUnsigned);
syn::custom_keyword!(HoldReason);
syn::custom_keyword!(exclude_parts);
syn::custom_keyword!(use_parts);
}
Expand Down Expand Up @@ -370,6 +371,7 @@ pub enum PalletPartKeyword {
Origin(keyword::Origin),
Inherent(keyword::Inherent),
ValidateUnsigned(keyword::ValidateUnsigned),
HoldReason(keyword::HoldReason),
}

impl Parse for PalletPartKeyword {
Expand All @@ -392,6 +394,8 @@ impl Parse for PalletPartKeyword {
Ok(Self::Inherent(input.parse()?))
} else if lookahead.peek(keyword::ValidateUnsigned) {
Ok(Self::ValidateUnsigned(input.parse()?))
} else if lookahead.peek(keyword::HoldReason) {
Ok(Self::HoldReason(input.parse()?))
} else {
Err(lookahead.error())
}
Expand All @@ -410,6 +414,7 @@ impl PalletPartKeyword {
Self::Origin(_) => "Origin",
Self::Inherent(_) => "Inherent",
Self::ValidateUnsigned(_) => "ValidateUnsigned",
Self::HoldReason(_) => "HoldReason",
}
}

Expand All @@ -435,6 +440,7 @@ impl Spanned for PalletPartKeyword {
Self::Origin(inner) => inner.span(),
Self::Inherent(inner) => inner.span(),
Self::ValidateUnsigned(inner) => inner.span(),
Self::HoldReason(inner) => inner.span(),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream {
let validate_unsigned_part =
def.validate_unsigned.as_ref().map(|_| quote::quote!(ValidateUnsigned,));

let hold_reason_part = def.hold_reason.as_ref().map(|_| quote::quote!(HoldReason,));

quote::quote!(
// This macro follows the conventions as laid out by the `tt-call` crate. It does not
// accept any arguments and simply returns the pallet parts, separated by commas, then
Expand All @@ -70,7 +72,7 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream {
tokens = [{
::{
Pallet, #call_part #storage_part #event_part #origin_part #config_part
#inherent_part #validate_unsigned_part
#inherent_part #validate_unsigned_part #hold_reason_part
}
}]
}
Expand Down
2 changes: 1 addition & 1 deletion frame/support/procedural/src/pallet/parse/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl EventDef {
let item = if let syn::Item::Enum(item) = item {
item
} else {
return Err(syn::Error::new(item.span(), "Invalid pallet::event, expected item enum"))
return Err(syn::Error::new(item.span(), "Invalid pallet::event, expected enum item"))
};

let event_attrs: Vec<PalletEventDepositAttr> =
Expand Down
86 changes: 86 additions & 0 deletions frame/support/procedural/src/pallet/parse/hold_reason.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// This file is part of Substrate.

// Copyright (C) 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.

use quote::ToTokens;
use syn::spanned::Spanned;

mod keyword {
syn::custom_keyword!(HoldReason);
}

pub struct HoldReasonDef {
/// The index of the HoldReason item in the pallet module.
pub index: usize,
/// The HoldReason keyword used (contains span).
pub hold_reason: keyword::HoldReason,
/// The span of the pallet::hold_reason attribute.
pub attr_span: proc_macro2::Span,
}

impl HoldReasonDef {
pub fn try_from(
attr_span: proc_macro2::Span,
index: usize,
scrate: &proc_macro2::Ident,
item: &mut syn::Item,
) -> syn::Result<Self> {
let item = if let syn::Item::Enum(item) = item {
item
} else {
return Err(syn::Error::new(
item.span(),
"Invalid pallet::hold_reason, expected enum item",
))
};

if !matches!(item.vis, syn::Visibility::Public(_)) {
let msg = "Invalid pallet::hold_reason, `HoldReason` must be public";
return Err(syn::Error::new(item.span(), msg))
}

let has_derive_attr = item
.attrs
.iter()
.find(|attr| {
attr.parse_meta()
.ok()
.map(|meta| match meta {
syn::Meta::List(syn::MetaList { path, .. }) =>
path.get_ident().map(|ident| ident == "derive").unwrap_or(false),
_ => false,
})
.unwrap_or(false)
})
.is_some();

if !has_derive_attr {
let derive_attr: syn::Attribute = syn::parse_quote! {
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
#scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen,
#scrate::scale_info::TypeInfo,
#scrate::RuntimeDebug,
)]
};
item.attrs.push(derive_attr);
}

let hold_reason = syn::parse2::<keyword::HoldReason>(item.ident.to_token_stream())?;

Ok(HoldReasonDef { index, hold_reason, attr_span })
}
}
16 changes: 16 additions & 0 deletions frame/support/procedural/src/pallet/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub mod extra_constants;
pub mod genesis_build;
pub mod genesis_config;
pub mod helper;
pub mod hold_reason;
pub mod hooks;
pub mod inherent;
pub mod origin;
Expand Down Expand Up @@ -56,6 +57,7 @@ pub struct Def {
pub genesis_build: Option<genesis_build::GenesisBuildDef>,
pub validate_unsigned: Option<validate_unsigned::ValidateUnsignedDef>,
pub extra_constants: Option<extra_constants::ExtraConstantsDef>,
pub hold_reason: Option<hold_reason::HoldReasonDef>,
pub type_values: Vec<type_value::TypeValueDef>,
pub frame_system: syn::Ident,
pub frame_support: syn::Ident,
Expand Down Expand Up @@ -89,6 +91,7 @@ impl Def {
let mut genesis_build = None;
let mut validate_unsigned = None;
let mut extra_constants = None;
let mut hold_reason = None;
let mut storages = vec![];
let mut type_values = vec![];

Expand Down Expand Up @@ -135,6 +138,13 @@ impl Def {
Some(PalletAttr::ExtraConstants(_)) =>
extra_constants =
Some(extra_constants::ExtraConstantsDef::try_from(index, item)?),
Some(PalletAttr::HoldReason(span)) =>
hold_reason = Some(hold_reason::HoldReasonDef::try_from(
span,
index,
&frame_support,
item,
)?),
Some(attr) => {
let msg = "Invalid duplicated attribute";
return Err(syn::Error::new(attr.span(), msg))
Expand Down Expand Up @@ -171,6 +181,7 @@ impl Def {
origin,
inherent,
storages,
hold_reason,
type_values,
frame_system,
frame_support,
Expand Down Expand Up @@ -385,6 +396,7 @@ mod keyword {
syn::custom_keyword!(generate_store);
syn::custom_keyword!(Store);
syn::custom_keyword!(extra_constants);
syn::custom_keyword!(hold_reason);
}

/// Parse attributes for item in pallet module
Expand All @@ -404,6 +416,7 @@ enum PalletAttr {
ValidateUnsigned(proc_macro2::Span),
TypeValue(proc_macro2::Span),
ExtraConstants(proc_macro2::Span),
HoldReason(proc_macro2::Span),
}

impl PalletAttr {
Expand All @@ -423,6 +436,7 @@ impl PalletAttr {
Self::ValidateUnsigned(span) => *span,
Self::TypeValue(span) => *span,
Self::ExtraConstants(span) => *span,
Self::HoldReason(span) => *span,
}
}
}
Expand Down Expand Up @@ -464,6 +478,8 @@ impl syn::parse::Parse for PalletAttr {
Ok(PalletAttr::TypeValue(content.parse::<keyword::type_value>()?.span()))
} else if lookahead.peek(keyword::extra_constants) {
Ok(PalletAttr::ExtraConstants(content.parse::<keyword::extra_constants>()?.span()))
} else if lookahead.peek(keyword::hold_reason) {
Ok(PalletAttr::HoldReason(content.parse::<keyword::hold_reason>()?.span()))
} else {
Err(lookahead.error())
}
Expand Down
12 changes: 12 additions & 0 deletions frame/support/test/tests/pallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,11 @@ pub mod pallet {
}
}

#[pallet::hold_reason]
pub enum HoldReason {
Staking,
}

#[derive(codec::Encode, sp_runtime::RuntimeDebug)]
#[cfg_attr(feature = "std", derive(codec::Decode))]
pub enum InherentError {
Expand Down Expand Up @@ -974,6 +979,13 @@ fn validate_unsigned_expand() {
assert_eq!(validity, ValidTransaction::default());
}

#[test]
fn hold_reason_expand() {
let hold_reason: RuntimeHoldReason = pallet::HoldReason::Staking.into();

assert_eq!(hold_reason, RuntimeHoldReason::Example(pallet::HoldReason::Staking));
}

#[test]
fn pallet_expand_deposit_event() {
TestExternalities::default().execute_with(|| {
Expand Down
14 changes: 14 additions & 0 deletions frame/support/test/tests/pallet_ui/hold_reason_non_enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#[frame_support::pallet]
mod pallet {
#[pallet::config]
pub trait Config: frame_system::Config {}

#[pallet::pallet]
pub struct Pallet<T>(core::marker::PhantomData<T>);

#[pallet::hold_reason]
pub struct HoldReason;
}

fn main() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: Invalid pallet::hold_reason, expected enum item
--> tests/pallet_ui/hold_reason_non_enum.rs:10:2
|
10 | pub struct HoldReason;
| ^^^
14 changes: 14 additions & 0 deletions frame/support/test/tests/pallet_ui/hold_reason_not_pub.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#[frame_support::pallet]
mod pallet {
#[pallet::config]
pub trait Config: frame_system::Config {}

#[pallet::pallet]
pub struct Pallet<T>(core::marker::PhantomData<T>);

#[pallet::hold_reason]
enum HoldReason {}
}

fn main() {
}
Loading