Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit dc5050b

Browse files
committed
Implement #[pallet::hold_reason]
1 parent 1184143 commit dc5050b

File tree

13 files changed

+230
-2
lines changed

13 files changed

+230
-2
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) 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+
use crate::construct_runtime::{parse::PalletPath, Pallet};
19+
use proc_macro2::{Ident, TokenStream};
20+
use quote::quote;
21+
22+
pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream {
23+
let mut conversion_fns = Vec::new();
24+
let mut hold_reason_variants = Vec::new();
25+
for decl in pallet_decls {
26+
if let Some(_) = decl.find_part("HoldReason") {
27+
let variant_name = &decl.name;
28+
let path = &decl.path;
29+
let index = &decl.index;
30+
31+
conversion_fns.push(expand_conversion_fn(path, variant_name));
32+
33+
hold_reason_variants.push(quote! {
34+
#[codec(index = #index)]
35+
#variant_name(#path::HoldReason),
36+
});
37+
}
38+
}
39+
40+
quote! {
41+
#[derive(
42+
Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
43+
#scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen,
44+
#scrate::scale_info::TypeInfo,
45+
#scrate::RuntimeDebug,
46+
)]
47+
pub enum RuntimeHoldReason {
48+
#( #hold_reason_variants )*
49+
}
50+
51+
#( #conversion_fns )*
52+
}
53+
}
54+
55+
fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream {
56+
quote! {
57+
impl From<#path::HoldReason> for RuntimeHoldReason {
58+
fn from(hr: #path::HoldReason) -> Self {
59+
RuntimeHoldReason::#variant_name(hr)
60+
}
61+
}
62+
}
63+
}

frame/support/procedural/src/construct_runtime/expand/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
mod call;
1919
mod config;
2020
mod event;
21+
mod hold_reason;
2122
mod inherent;
2223
mod metadata;
2324
mod origin;
@@ -26,6 +27,7 @@ mod unsigned;
2627
pub use call::expand_outer_dispatch;
2728
pub use config::expand_outer_config;
2829
pub use event::expand_outer_event;
30+
pub use hold_reason::expand_outer_hold_reason;
2931
pub use inherent::expand_outer_inherent;
3032
pub use metadata::expand_runtime_metadata;
3133
pub use origin::expand_outer_origin;

frame/support/procedural/src/construct_runtime/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ fn construct_runtime_final_expansion(
265265
let inherent =
266266
expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate);
267267
let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate);
268+
let hold_reason = expand::expand_outer_hold_reason(&pallets, &scrate);
268269
let integrity_test = decl_integrity_test(&scrate);
269270
let static_assertions = decl_static_assertions(&name, &pallets, &scrate);
270271

@@ -307,6 +308,8 @@ fn construct_runtime_final_expansion(
307308

308309
#validate_unsigned
309310

311+
#hold_reason
312+
310313
#integrity_test
311314

312315
#static_assertions

frame/support/procedural/src/construct_runtime/parse.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ mod keyword {
3838
syn::custom_keyword!(Origin);
3939
syn::custom_keyword!(Inherent);
4040
syn::custom_keyword!(ValidateUnsigned);
41+
syn::custom_keyword!(HoldReason);
4142
syn::custom_keyword!(exclude_parts);
4243
syn::custom_keyword!(use_parts);
4344
}
@@ -370,6 +371,7 @@ pub enum PalletPartKeyword {
370371
Origin(keyword::Origin),
371372
Inherent(keyword::Inherent),
372373
ValidateUnsigned(keyword::ValidateUnsigned),
374+
HoldReason(keyword::HoldReason),
373375
}
374376

375377
impl Parse for PalletPartKeyword {
@@ -392,6 +394,8 @@ impl Parse for PalletPartKeyword {
392394
Ok(Self::Inherent(input.parse()?))
393395
} else if lookahead.peek(keyword::ValidateUnsigned) {
394396
Ok(Self::ValidateUnsigned(input.parse()?))
397+
} else if lookahead.peek(keyword::HoldReason) {
398+
Ok(Self::HoldReason(input.parse()?))
395399
} else {
396400
Err(lookahead.error())
397401
}
@@ -410,6 +414,7 @@ impl PalletPartKeyword {
410414
Self::Origin(_) => "Origin",
411415
Self::Inherent(_) => "Inherent",
412416
Self::ValidateUnsigned(_) => "ValidateUnsigned",
417+
Self::HoldReason(_) => "HoldReason",
413418
}
414419
}
415420

@@ -435,6 +440,7 @@ impl Spanned for PalletPartKeyword {
435440
Self::Origin(inner) => inner.span(),
436441
Self::Inherent(inner) => inner.span(),
437442
Self::ValidateUnsigned(inner) => inner.span(),
443+
Self::HoldReason(inner) => inner.span(),
438444
}
439445
}
440446
}

frame/support/procedural/src/pallet/expand/tt_default_parts.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream {
4848
let validate_unsigned_part =
4949
def.validate_unsigned.as_ref().map(|_| quote::quote!(ValidateUnsigned,));
5050

51+
let hold_reason_part = def.hold_reason.as_ref().map(|_| quote::quote!(HoldReason,));
52+
5153
quote::quote!(
5254
// This macro follows the conventions as laid out by the `tt-call` crate. It does not
5355
// accept any arguments and simply returns the pallet parts, separated by commas, then
@@ -70,7 +72,7 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream {
7072
tokens = [{
7173
::{
7274
Pallet, #call_part #storage_part #event_part #origin_part #config_part
73-
#inherent_part #validate_unsigned_part
75+
#inherent_part #validate_unsigned_part #hold_reason_part
7476
}
7577
}]
7678
}

frame/support/procedural/src/pallet/parse/event.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl EventDef {
104104
let item = if let syn::Item::Enum(item) = item {
105105
item
106106
} else {
107-
return Err(syn::Error::new(item.span(), "Invalid pallet::event, expected item enum"))
107+
return Err(syn::Error::new(item.span(), "Invalid pallet::event, expected enum item"))
108108
};
109109

110110
let event_attrs: Vec<PalletEventDepositAttr> =
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) 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+
use quote::ToTokens;
19+
use syn::spanned::Spanned;
20+
21+
mod keyword {
22+
syn::custom_keyword!(HoldReason);
23+
}
24+
25+
pub struct HoldReasonDef {
26+
/// The index of the HoldReason item in the pallet module.
27+
pub index: usize,
28+
/// The HoldReason keyword used (contains span).
29+
pub hold_reason: keyword::HoldReason,
30+
/// The span of the pallet::hold_reason attribute.
31+
pub attr_span: proc_macro2::Span,
32+
}
33+
34+
impl HoldReasonDef {
35+
pub fn try_from(
36+
attr_span: proc_macro2::Span,
37+
index: usize,
38+
scrate: &proc_macro2::Ident,
39+
item: &mut syn::Item,
40+
) -> syn::Result<Self> {
41+
let item = if let syn::Item::Enum(item) = item {
42+
item
43+
} else {
44+
return Err(syn::Error::new(
45+
item.span(),
46+
"Invalid pallet::hold_reason, expected enum item",
47+
))
48+
};
49+
50+
if !matches!(item.vis, syn::Visibility::Public(_)) {
51+
let msg = "Invalid pallet::hold_reason, `HoldReason` must be public";
52+
return Err(syn::Error::new(item.span(), msg))
53+
}
54+
55+
let has_derive_attr = item
56+
.attrs
57+
.iter()
58+
.find(|attr| {
59+
attr.parse_meta()
60+
.ok()
61+
.map(|meta| match meta {
62+
syn::Meta::List(syn::MetaList { path, .. }) =>
63+
path.get_ident().map(|ident| ident == "derive").unwrap_or(false),
64+
_ => false,
65+
})
66+
.unwrap_or(false)
67+
})
68+
.is_some();
69+
70+
if !has_derive_attr {
71+
let derive_attr: syn::Attribute = syn::parse_quote! {
72+
#[derive(
73+
Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
74+
#scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen,
75+
#scrate::scale_info::TypeInfo,
76+
#scrate::RuntimeDebug,
77+
)]
78+
};
79+
item.attrs.push(derive_attr);
80+
}
81+
82+
let hold_reason = syn::parse2::<keyword::HoldReason>(item.ident.to_token_stream())?;
83+
84+
Ok(HoldReasonDef { index, hold_reason, attr_span })
85+
}
86+
}

frame/support/procedural/src/pallet/parse/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub mod extra_constants;
2727
pub mod genesis_build;
2828
pub mod genesis_config;
2929
pub mod helper;
30+
pub mod hold_reason;
3031
pub mod hooks;
3132
pub mod inherent;
3233
pub mod origin;
@@ -56,6 +57,7 @@ pub struct Def {
5657
pub genesis_build: Option<genesis_build::GenesisBuildDef>,
5758
pub validate_unsigned: Option<validate_unsigned::ValidateUnsignedDef>,
5859
pub extra_constants: Option<extra_constants::ExtraConstantsDef>,
60+
pub hold_reason: Option<hold_reason::HoldReasonDef>,
5961
pub type_values: Vec<type_value::TypeValueDef>,
6062
pub frame_system: syn::Ident,
6163
pub frame_support: syn::Ident,
@@ -89,6 +91,7 @@ impl Def {
8991
let mut genesis_build = None;
9092
let mut validate_unsigned = None;
9193
let mut extra_constants = None;
94+
let mut hold_reason = None;
9295
let mut storages = vec![];
9396
let mut type_values = vec![];
9497

@@ -135,6 +138,13 @@ impl Def {
135138
Some(PalletAttr::ExtraConstants(_)) =>
136139
extra_constants =
137140
Some(extra_constants::ExtraConstantsDef::try_from(index, item)?),
141+
Some(PalletAttr::HoldReason(span)) =>
142+
hold_reason = Some(hold_reason::HoldReasonDef::try_from(
143+
span,
144+
index,
145+
&frame_support,
146+
item,
147+
)?),
138148
Some(attr) => {
139149
let msg = "Invalid duplicated attribute";
140150
return Err(syn::Error::new(attr.span(), msg))
@@ -171,6 +181,7 @@ impl Def {
171181
origin,
172182
inherent,
173183
storages,
184+
hold_reason,
174185
type_values,
175186
frame_system,
176187
frame_support,
@@ -385,6 +396,7 @@ mod keyword {
385396
syn::custom_keyword!(generate_store);
386397
syn::custom_keyword!(Store);
387398
syn::custom_keyword!(extra_constants);
399+
syn::custom_keyword!(hold_reason);
388400
}
389401

390402
/// Parse attributes for item in pallet module
@@ -404,6 +416,7 @@ enum PalletAttr {
404416
ValidateUnsigned(proc_macro2::Span),
405417
TypeValue(proc_macro2::Span),
406418
ExtraConstants(proc_macro2::Span),
419+
HoldReason(proc_macro2::Span),
407420
}
408421

409422
impl PalletAttr {
@@ -423,6 +436,7 @@ impl PalletAttr {
423436
Self::ValidateUnsigned(span) => *span,
424437
Self::TypeValue(span) => *span,
425438
Self::ExtraConstants(span) => *span,
439+
Self::HoldReason(span) => *span,
426440
}
427441
}
428442
}
@@ -464,6 +478,8 @@ impl syn::parse::Parse for PalletAttr {
464478
Ok(PalletAttr::TypeValue(content.parse::<keyword::type_value>()?.span()))
465479
} else if lookahead.peek(keyword::extra_constants) {
466480
Ok(PalletAttr::ExtraConstants(content.parse::<keyword::extra_constants>()?.span()))
481+
} else if lookahead.peek(keyword::hold_reason) {
482+
Ok(PalletAttr::HoldReason(content.parse::<keyword::hold_reason>()?.span()))
467483
} else {
468484
Err(lookahead.error())
469485
}

frame/support/test/tests/pallet.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,11 @@ pub mod pallet {
476476
}
477477
}
478478

479+
#[pallet::hold_reason]
480+
pub enum HoldReason {
481+
Staking,
482+
}
483+
479484
#[derive(codec::Encode, sp_runtime::RuntimeDebug)]
480485
#[cfg_attr(feature = "std", derive(codec::Decode))]
481486
pub enum InherentError {
@@ -974,6 +979,13 @@ fn validate_unsigned_expand() {
974979
assert_eq!(validity, ValidTransaction::default());
975980
}
976981

982+
#[test]
983+
fn hold_reason_expand() {
984+
let hold_reason: RuntimeHoldReason = pallet::HoldReason::Staking.into();
985+
986+
assert_eq!(hold_reason, RuntimeHoldReason::Example(pallet::HoldReason::Staking));
987+
}
988+
977989
#[test]
978990
fn pallet_expand_deposit_event() {
979991
TestExternalities::default().execute_with(|| {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#[frame_support::pallet]
2+
mod pallet {
3+
#[pallet::config]
4+
pub trait Config: frame_system::Config {}
5+
6+
#[pallet::pallet]
7+
pub struct Pallet<T>(core::marker::PhantomData<T>);
8+
9+
#[pallet::hold_reason]
10+
pub struct HoldReason;
11+
}
12+
13+
fn main() {
14+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: Invalid pallet::hold_reason, expected enum item
2+
--> tests/pallet_ui/hold_reason_non_enum.rs:10:2
3+
|
4+
10 | pub struct HoldReason;
5+
| ^^^
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#[frame_support::pallet]
2+
mod pallet {
3+
#[pallet::config]
4+
pub trait Config: frame_system::Config {}
5+
6+
#[pallet::pallet]
7+
pub struct Pallet<T>(core::marker::PhantomData<T>);
8+
9+
#[pallet::hold_reason]
10+
enum HoldReason {}
11+
}
12+
13+
fn main() {
14+
}

0 commit comments

Comments
 (0)