Adds syntax for marking calls feeless (#1926)

Fixes https://github.com/paritytech/polkadot-sdk/issues/1725

This PR adds the following changes:
1. An attribute `pallet::feeless_if` that can be optionally attached to
a call like so:
```rust
#[pallet::feeless_if(|_origin: &OriginFor<T>, something: &u32| -> bool {
	*something == 0
})]
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
     ....
}
```
The closure passed accepts references to arguments as specified in the
call fn. It returns a boolean that denotes the conditions required for
this call to be "feeless".

2. A signed extension `SkipCheckIfFeeless<T: SignedExtension>` that
wraps a transaction payment processor such as
`pallet_transaction_payment::ChargeTransactionPayment`. It checks for
all calls annotated with `pallet::feeless_if` to see if the conditions
are met. If so, the wrapped signed extension is not called, essentially
making the call feeless.

In order to use this, you can simply replace your existing signed
extension that manages transaction payment like so:
```diff
- pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
+ pallet_skip_feeless_payment::SkipCheckIfFeeless<
+	Runtime,
+	pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
+ >,
```

### Todo
- [x] Tests
- [x] Docs
- [x] Prdoc

---------

Co-authored-by: Nikhil Gupta <>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
This commit is contained in:
gupnik
2023-11-13 19:14:41 +05:30
committed by GitHub
parent ebcf0a0f1c
commit 60c77a2e9a
33 changed files with 874 additions and 54 deletions
@@ -0,0 +1,37 @@
// 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.
#[frame_support::pallet(dev_mode)]
mod pallet {
use frame_support::pallet_prelude::DispatchResult;
use frame_system::pallet_prelude::OriginFor;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(core::marker::PhantomData<T>);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::feeless_if(|| -> bool { true })]
pub fn foo(_: OriginFor<T>) -> DispatchResult { Ok(()) }
}
}
fn main() {
}
@@ -0,0 +1,5 @@
error: Invalid pallet::call, feeless_if closure must have same number of arguments as the dispatchable function
--> tests/pallet_ui/call_feeless_invalid_closure_arg1.rs:31:24
|
31 | #[pallet::feeless_if(|| -> bool { true })]
| ^
@@ -0,0 +1,37 @@
// 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.
#[frame_support::pallet(dev_mode)]
mod pallet {
use frame_support::pallet_prelude::DispatchResult;
use frame_system::pallet_prelude::OriginFor;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(core::marker::PhantomData<T>);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::feeless_if(|_: bool| -> bool { true })]
pub fn foo(_: OriginFor<T>) -> DispatchResult { Ok(()) }
}
}
fn main() {
}
@@ -0,0 +1,5 @@
error: Invalid type: expected `&OriginFor<T>`
--> tests/pallet_ui/call_feeless_invalid_closure_arg2.rs:31:28
|
31 | #[pallet::feeless_if(|_: bool| -> bool { true })]
| ^^^^
@@ -0,0 +1,37 @@
// 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.
#[frame_support::pallet(dev_mode)]
mod pallet {
use frame_support::pallet_prelude::DispatchResult;
use frame_system::pallet_prelude::OriginFor;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(core::marker::PhantomData<T>);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::feeless_if(|_: &OriginFor<T>, _s: &u32| -> bool { true })]
pub fn foo(_: OriginFor<T>, _something: u64) -> DispatchResult { Ok(()) }
}
}
fn main() {
}
@@ -0,0 +1,5 @@
error: Invalid pallet::call, feeless_if closure argument must have a reference to the same type as the dispatchable function argument
--> tests/pallet_ui/call_feeless_invalid_closure_arg3.rs:31:43
|
31 | #[pallet::feeless_if(|_: &OriginFor<T>, _s: &u32| -> bool { true })]
| ^^
@@ -0,0 +1,37 @@
// 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.
#[frame_support::pallet(dev_mode)]
mod pallet {
use frame_support::pallet_prelude::DispatchResult;
use frame_system::pallet_prelude::OriginFor;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(core::marker::PhantomData<T>);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::feeless_if(|_: &OriginFor<T>| -> u32 { 0 })]
pub fn foo(_: OriginFor<T>) -> DispatchResult { Ok(()) }
}
}
fn main() {
}
@@ -0,0 +1,5 @@
error: Invalid pallet::call, feeless_if closure must return `bool`
--> tests/pallet_ui/call_feeless_invalid_closure_return.rs:31:43
|
31 | #[pallet::feeless_if(|_: &OriginFor<T>| -> u32 { 0 })]
| ^
@@ -0,0 +1,37 @@
// 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.
#[frame_support::pallet(dev_mode)]
mod pallet {
use frame_support::pallet_prelude::DispatchResult;
use frame_system::pallet_prelude::OriginFor;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(core::marker::PhantomData<T>);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::feeless_if(0)]
pub fn foo(_: OriginFor<T>) -> DispatchResult { Ok(()) }
}
}
fn main() {
}
@@ -0,0 +1,11 @@
error: Invalid feeless_if attribute: expected a closure
--> tests/pallet_ui/call_feeless_invalid_type.rs:31:24
|
31 | #[pallet::feeless_if(0)]
| ^
error: expected `|`
--> tests/pallet_ui/call_feeless_invalid_type.rs:31:24
|
31 | #[pallet::feeless_if(0)]
| ^
@@ -1,4 +1,4 @@
error: expected `weight` or `call_index`
error: expected one of: `weight`, `call_index`, `feeless_if`
--> tests/pallet_ui/call_invalid_attr.rs:31:13
|
31 | #[pallet::weird_attr]
@@ -3,9 +3,3 @@ error: Invalid type: expected `OriginFor<T>`
|
34 | pub fn foo(origin: u8) {}
| ^^
error: expected `OriginFor`
--> tests/pallet_ui/call_invalid_origin_type.rs:34:22
|
34 | pub fn foo(origin: u8) {}
| ^^
@@ -0,0 +1,37 @@
// 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.
#[frame_support::pallet(dev_mode)]
mod pallet {
use frame_support::pallet_prelude::DispatchResult;
use frame_system::pallet_prelude::OriginFor;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(core::marker::PhantomData<T>);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::feeless_if(|_: &OriginFor<T>| -> bool { true })]
pub fn foo(_: OriginFor<T>) -> DispatchResult { Ok(()) }
}
}
fn main() {
}