Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tx ext stage 2: 2/4] Introduce #[pallet::authorize(...)] macro attribute and AuthorizeCall system transaction extension #6324

Open
wants to merge 38 commits into
base: master
Choose a base branch
from

Conversation

gui1117
Copy link
Contributor

@gui1117 gui1117 commented Nov 1, 2024

Meta

This PR is part of 4 PR:

Description

  • new attribute #[pallet::authorize(..)], this attributes takes a function which returns the validity of the call.
  • new attribute #[pallet::weight_of_authorize(..)], same as #[pallet::weight(..)] defines the pre dispatch weight of the authorize function. It can also be retrieved from WeightInfo under the name: authorize_$call_name.
  • new trait Authorize in frame-support: implemented on the call for pallets and runtime, and used by AuthorizeCall transaction extension in frame-system.
  • new origin variant in frame origin: Origin::Authorized: a bit similar to Unsigned but used for general transactions.
  • new transaction extension: AuthorizeCall in frame system. This is meant to be used first in the transaction extension pipeline. It will call the authorize function and change the origin to authorized
  • new method: ensure_authorized.

Usage

# #[allow(unused)]
#[frame_support::pallet]
pub mod pallet {
    use frame_support::pallet_prelude::*;
    use frame_system::pallet_prelude::*;
                                                                                   
    #[pallet::pallet]
    pub struct Pallet<T>(_);
                                                                                   
    #[pallet::config]
    pub trait Config: frame_system::Config {}
                                                                                   
    #[pallet::call]
    impl<T: Config> Pallet<T> {
        #[pallet::weight(Weight::zero())]
        #[pallet::authorize(|_source, foo| if *foo == 42 {
            let refund = Weight::zero();
            let validity = ValidTransaction::default();
            Ok((validity, refund))
        } else {
            Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
        })]
        #[pallet::weight_of_authorize(Weight::zero())]
        #[pallet::call_index(0)]
        pub fn some_call(origin: OriginFor<T>, arg: u32) -> DispatchResult {
            ensure_authorized(origin)?;
                                                                                   
            Ok(())
        }
                                                                                   
        #[pallet::weight(Weight::zero())]
        // We can also give the callback as a function
        #[pallet::authorize(Pallet::<T>::authorize_some_other_call)]
        #[pallet::weight_of_authorize(Weight::zero())]
        #[pallet::call_index(1)]
        pub fn some_other_call(origin: OriginFor<T>, arg: u32) -> DispatchResult {
            ensure_authorized(origin)?;
                                                                                   
            Ok(())
        }
    }
                                                                                   
    impl<T: Config> Pallet<T> {
        fn authorize_some_other_call(
            source: TransactionSource,
            foo: &u32
        ) -> TransactionValidityWithRefund {
            if *foo == 42 {
                let refund = Weight::zero();
                let validity = ValidTransaction::default();
                Ok((validity, refund))
            } else {
                Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
            }
        }
    }
                                                                                   
    #[frame_benchmarking::v2::benchmarks]
    mod benchmarks {
        use super::*;
        use frame_benchmarking::v2::BenchmarkError;
                                                                                   
        #[benchmark]
        fn authorize_some_call() -> Result<(), BenchmarkError> {
            let call = Call::<T>::some_call { arg: 42 };
                                                                                   
            #[block]
            {
                use frame_support::pallet_prelude::Authorize;
                call.authorize(TransactionSource::External)
                    .ok_or("Call must give some authorization")??;
            }
                                                                                   
            Ok(())
        }
    }
}

@gui1117 gui1117 changed the title Introduce #[pallet::authorize(...)] macro attribute and AuthorizeCall system transaction extension [2/4] Introduce #[pallet::authorize(...)] macro attribute and AuthorizeCall system transaction extension Nov 1, 2024
@gui1117 gui1117 changed the title [2/4] Introduce #[pallet::authorize(...)] macro attribute and AuthorizeCall system transaction extension [Tx ext stage 2: 2/4] Introduce #[pallet::authorize(...)] macro attribute and AuthorizeCall system transaction extension Nov 1, 2024
@gui1117 gui1117 added the T1-FRAME This PR/Issue is related to core FRAME, the framework. label Nov 1, 2024
@gui1117 gui1117 marked this pull request as ready for review November 1, 2024 12:33
@gui1117 gui1117 requested a review from a team as a code owner November 1, 2024 12:33
github-merge-queue bot pushed a commit that referenced this pull request Nov 13, 2024
…tionExtension::validate` (#6323)

## Meta 

This PR is part of 4 PR:
* #6323
* #6324
* #6325
* #6326

## Description

One goal of transaction extension is to get rid or unsigned
transactions.
But unsigned transaction validation has access to the
`TransactionSource`.

The source is used for unsigned transactions that the node trust and
don't want to pay upfront.
Instead of using transaction source we could do: the transaction is
valid if it is signed by the block author, conceptually it should work,
but it doesn't look so easy.

This PR add `TransactionSource` to the validate function for transaction
extensions
github-merge-queue bot pushed a commit that referenced this pull request Nov 13, 2024
…tionExtension::validate` (#6323)

## Meta 

This PR is part of 4 PR:
* #6323
* #6324
* #6325
* #6326

## Description

One goal of transaction extension is to get rid or unsigned
transactions.
But unsigned transaction validation has access to the
`TransactionSource`.

The source is used for unsigned transactions that the node trust and
don't want to pay upfront.
Instead of using transaction source we could do: the transaction is
valid if it is signed by the block author, conceptually it should work,
but it doesn't look so easy.

This PR add `TransactionSource` to the validate function for transaction
extensions
Base automatically changed from gui-tx-ext-stage-2-part-1 to master November 13, 2024 10:12
gui1117 added a commit that referenced this pull request Nov 14, 2024
…tionExtension::validate` (#6323)

## Meta

This PR is part of 4 PR:
* #6323
* #6324
* #6325
* #6326

## Description

One goal of transaction extension is to get rid or unsigned
transactions.
But unsigned transaction validation has access to the
`TransactionSource`.

The source is used for unsigned transactions that the node trust and
don't want to pay upfront.
Instead of using transaction source we could do: the transaction is
valid if it is signed by the block author, conceptually it should work,
but it doesn't look so easy.

This PR add `TransactionSource` to the validate function for transaction
extensions

(cherry picked from commit 8e3d929)
gui1117 added a commit that referenced this pull request Nov 15, 2024
…tionExtension::validate` (#6323)

## Meta

This PR is part of 4 PR:
* #6323
* #6324
* #6325
* #6326

## Description

One goal of transaction extension is to get rid or unsigned
transactions.
But unsigned transaction validation has access to the
`TransactionSource`.

The source is used for unsigned transactions that the node trust and
don't want to pay upfront.
Instead of using transaction source we could do: the transaction is
valid if it is signed by the block author, conceptually it should work,
but it doesn't look so easy.

This PR add `TransactionSource` to the validate function for transaction
extensions

(cherry picked from commit 8e3d929)
Copy link
Contributor

@georgepisaltu georgepisaltu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, just some comments and questions

fn authorize(
&self,
source: TransactionSource,
) -> Option<Result<(ValidTransaction, Weight), TransactionValidityError>>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth mentioning that generally when we have an Option<Result<(... we should have a dedicated type for the return, but I think this will never be manually implemented and having it like this makes it easier to work with in the macros. Users get to see TransactionValidityWithRefund as the authorize closure return type, so in terms of UX it's good.

prdoc/pr_6323.prdoc Outdated Show resolved Hide resolved
substrate/frame/examples/kitchensink/src/weights.rs Outdated Show resolved Hide resolved
substrate/frame/support/procedural/Cargo.toml Outdated Show resolved Hide resolved
substrate/frame/support/test/tests/authorize.rs Outdated Show resolved Hide resolved
substrate/frame/system/src/extensions/authorize_call.rs Outdated Show resolved Hide resolved
substrate/frame/system/src/extensions/authorize_call.rs Outdated Show resolved Hide resolved
substrate/bin/node/runtime/src/lib.rs Show resolved Hide resolved
@gui1117 gui1117 requested a review from a team as a code owner November 20, 2024 11:05
@paritytech paritytech deleted a comment from github-actions bot Dec 5, 2024
@paritytech paritytech deleted a comment from github-actions bot Dec 5, 2024
@paritytech paritytech deleted a comment from github-actions bot Dec 5, 2024
@paritytech paritytech deleted a comment from github-actions bot Dec 5, 2024
@paritytech paritytech deleted a comment from github-actions bot Dec 5, 2024
@paritytech paritytech deleted a comment from github-actions bot Dec 5, 2024
@paritytech paritytech deleted a comment from github-actions bot Dec 5, 2024
@paritytech paritytech deleted a comment from github-actions bot Dec 5, 2024
@gui1117
Copy link
Contributor Author

gui1117 commented Dec 7, 2024

PR is green, but semver is failing with:

[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] lifetime = "'a"
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] outlives = [
    "'static",
]
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] lifetime = "'a"
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] outlives = [
    "'static",
]
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] lifetime = "'a"
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] outlives = [
    "'static",
]
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] lifetime = "'a"
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] outlives = [
    "'static",
]
(4/50) building sp-runtime-31.0.1...
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] lifetime = "'a"
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] outlives = [
    "'static",
]
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] lifetime = "'a"
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] outlives = [
    "'static",
]
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] lifetime = "'a"
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] outlives = [
    "'static",
]
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] lifetime = "'a"
[/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/public-api-0.40.0/src/render.rs:907:17] outlives = [
    "'static",
]
(5/50) building frame-executive-HEAD...
(6/50) building frame-executive-28.0.0...
Error: Failed to build rustdoc JSON (see stderr)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T1-FRAME This PR/Issue is related to core FRAME, the framework.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants