Skip to content

Commit

Permalink
feat(fc-pallet-pass): add SkipCheckIfPassAccount
Browse files Browse the repository at this point in the history
This new extension skips certain checks (like `CheckNonce`) if the caller is a session key.

This extension should be deprecated in the future in favour of a couple of `TransactionExtension`s that: 1) issues an origin for the account, and 2) after checks like Nonce, replaces this custom origin with `frame_system::Origin::signed(account_key)`, where `account_key` is the `AccountId` of the account being authorized by `pallet-pass`.
  • Loading branch information
pandres95 committed Nov 19, 2024
1 parent 0058920 commit d6b77ae
Showing 1 changed file with 115 additions and 4 deletions.
119 changes: 115 additions & 4 deletions pallets/pass/src/extension.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
use core::marker::PhantomData;

use crate::{Config, Pallet};
use codec::{Decode, Encode};
use frame_support::pallet_prelude::TransactionValidityError;
use scale_info::{StaticTypeInfo, TypeInfo};
use sp_runtime::traits::{DispatchInfoOf, SignedExtension};

use crate::{Config, Pallet};

/// Changes the origin account to inner extensions if the signer is a session key, so the validations
/// and handling of these extensions (like charging to an account) happens on behalf of the `AccountId`
/// of the account this session key is being associated to.
///
/// In the future, this extension would be deprecated in favour of a couple of an extension that issues
/// authorized origins from `pallet-pass`.
#[derive(Encode, Decode)]
pub struct ChargeTransactionToPassAccount<S, T, I = ()>(S, PhantomData<(T, I)>);

Expand Down Expand Up @@ -67,6 +72,17 @@ where
self.0.additional_signed()
}

fn validate(
&self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> frame_support::pallet_prelude::TransactionValidity {
let who = Pallet::<T, I>::signer_from_session_key(who).unwrap_or(who.clone());
self.0.validate(&who, call, info, len)
}

fn pre_dispatch(
self,
who: &Self::AccountId,
Expand All @@ -78,24 +94,119 @@ where
self.0.pre_dispatch(&who, call, info, len)
}

fn post_dispatch(
pre: Option<Self::Pre>,
info: &DispatchInfoOf<Self::Call>,
post_info: &sp_runtime::traits::PostDispatchInfoOf<Self::Call>,
len: usize,
result: &sp_runtime::DispatchResult,
) -> Result<(), frame_support::pallet_prelude::TransactionValidityError> {
S::post_dispatch(pre, info, post_info, len, result)
}
}

/// Skips some checks (like [`frame_system::CheckNonce`]) if the caller is a session key.
///
/// This extension should be deprecated in the future in favour of a couple of `TransactionExtension`s
/// that:
///
/// 1. Issues a new custom origin from `pallet-pass` to wrap the account and skip checks. Then,
/// 2. After those checks, replaces this custom origin with [`frame_system::RawOrigin::Signed`],
/// where the signed `account_id` is the derived `AccountId` associated to the account handled by
/// `pallet-pass`.
#[derive(Encode, Decode)]
pub struct SkipCheckIfPassAccount<S, T, I = ()>(S, PhantomData<(T, I)>);

impl<S: SignedExtension, T, I> SkipCheckIfPassAccount<S, T, I> {
pub fn new(s: S) -> Self {
Self(s, PhantomData)
}
}

impl<S: Clone, T, I> Clone for SkipCheckIfPassAccount<S, T, I> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}

impl<S: Eq, T, I> Eq for SkipCheckIfPassAccount<S, T, I> {}
impl<S: PartialEq, T, I> PartialEq for SkipCheckIfPassAccount<S, T, I> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}

impl<S: SignedExtension + StaticTypeInfo, T, I> TypeInfo for SkipCheckIfPassAccount<S, T, I> {
type Identity = S;
fn type_info() -> scale_info::Type {
S::type_info()
}
}

impl<S: SignedExtension + Encode, T, I> core::fmt::Debug for SkipCheckIfPassAccount<S, T, I> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "SkipCheckIfPassAccount<{:?}>", self.0.encode())
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
Ok(())
}
}

impl<S, T, I> SignedExtension for SkipCheckIfPassAccount<S, T, I>
where
T: Config<I> + Send + Sync,
I: 'static + Send + Sync,
S: SignedExtension<AccountId = T::AccountId, Call = <T as frame_system::Config>::RuntimeCall>,
{
const IDENTIFIER: &'static str = S::IDENTIFIER;
type AccountId = S::AccountId;
type Call = S::Call;
type AdditionalSigned = S::AdditionalSigned;
type Pre = S::Pre;

fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
self.0.additional_signed()
}

fn validate(
&self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> frame_support::pallet_prelude::TransactionValidity {
let who = Pallet::<T, I>::signer_from_session_key(who).unwrap_or(who.clone());
if Pallet::<T, I>::signer_from_session_key(who).is_some() {
return Ok(Default::default());
}
self.0.validate(&who, call, info, len)
}

fn pre_dispatch(
self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
if Pallet::<T, I>::signer_from_session_key(who).is_some() {
return Ok((None, Default::default()));

Check failure on line 194 in pallets/pass/src/extension.rs

View workflow job for this annotation

GitHub Actions / clippy

mismatched types

error[E0308]: mismatched types --> pallets/pass/src/extension.rs:194:23 | 194 | return Ok((None, Default::default())); | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `(Option<_>, _)` | | | arguments to this enum variant are incorrect | = note: expected associated type `<S as sp_runtime::traits::SignedExtension>::Pre` found tuple `(std::option::Option<_>, _)` help: the type constructed contains `(std::option::Option<_>, _)` due to the type of the argument passed --> pallets/pass/src/extension.rs:194:20 | 194 | return Ok((None, Default::default())); | ^^^--------------------------^ | | | this argument influences the type of `Ok` note: tuple variant defined here --> /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/result.rs:531:5 help: consider constraining the associated type `<S as sp_runtime::traits::SignedExtension>::Pre` to `(std::option::Option<_>, _)` | 161 | S: SignedExtension<AccountId = T::AccountId, Call = <T as frame_system::Config>::RuntimeCall, Pre = (std::option::Option<_>, _)>, | +++++++++++++++++++++++++++++++++++
}
self.0.pre_dispatch(&who, call, info, len)
}

fn post_dispatch(
pre: Option<Self::Pre>,
info: &DispatchInfoOf<Self::Call>,
post_info: &sp_runtime::traits::PostDispatchInfoOf<Self::Call>,
len: usize,
result: &sp_runtime::DispatchResult,
) -> Result<(), frame_support::pallet_prelude::TransactionValidityError> {
S::post_dispatch(pre, info, post_info, len, result)
if let Some(pre) = pre {
S::post_dispatch(pre, info, post_info, len, result)

Check failure on line 207 in pallets/pass/src/extension.rs

View workflow job for this annotation

GitHub Actions / clippy

mismatched types

error[E0308]: mismatched types --> pallets/pass/src/extension.rs:207:30 | 207 | S::post_dispatch(pre, info, post_info, len, result) | ---------------- ^^^ expected `Option<<S as SignedExtension>::Pre>`, found associated type | | | arguments to this function are incorrect | = note: expected enum `std::option::Option<<S as sp_runtime::traits::SignedExtension>::Pre>` found associated type `<S as sp_runtime::traits::SignedExtension>::Pre` note: associated function defined here --> /home/runner/.cargo/git/checkouts/polkadot-sdk-9b4d86516933931c/d13cf29/substrate/primitives/runtime/src/traits.rs:1583:5 | 1583 | fn post_dispatch( | ^^^^^^^^^^^^^ help: consider constraining the associated type `<S as sp_runtime::traits::SignedExtension>::Pre` to `std::option::Option<<S as sp_runtime::traits::SignedExtension>::Pre>` | 161 | S: SignedExtension<AccountId = T::AccountId, Call = <T as frame_system::Config>::RuntimeCall, Pre = std::option::Option<<S as sp_runtime::traits::SignedExtension>::Pre>>, | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ help: try wrapping the expression in `Some` | 207 | S::post_dispatch(Some(pre), info, post_info, len, result) | +++++ +
} else {
Ok(())
}
}
}

0 comments on commit d6b77ae

Please sign in to comment.