Skip to content

Commit

Permalink
Use skip-feeless-payment pallet
Browse files Browse the repository at this point in the history
  • Loading branch information
JuaniRios committed Oct 10, 2024
1 parent 75a6225 commit 142908c
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 145 deletions.
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ pallet-staking = { version = "35.0.0", default-features = false }
pallet-proxy = { version = "35.0.0", default-features = false }
pallet-identity = { version = "35.0.0", default-features = false }
pallet-asset-tx-payment = { version = "35.0.0", default-features = false }
pallet-skip-feeless-payment = { version = "10.0.0", default-features = false }

# Polkadot (with default disabled)
pallet-xcm = { version = "14.0.0", default-features = false }
Expand Down
15 changes: 10 additions & 5 deletions integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ sp-consensus-aura.workspace = true
pallet-aura.workspace = true
pallet-session.workspace = true
pallet-proxy-bonding.workspace = true
pallet-skip-feeless-payment.workspace = true

# Runtimes
polkadot-runtime.workspace = true
Expand All @@ -100,7 +101,9 @@ std = [
"frame-system/std",
"itertools/use_std",
"orml-oracle/std",
"pallet-asset-tx-payment/std",
"pallet-assets/std",
"pallet-aura/std",
"pallet-balances/std",
"pallet-collective/std",
"pallet-democracy/std",
Expand All @@ -112,7 +115,10 @@ std = [
"pallet-membership/std",
"pallet-message-queue/std",
"pallet-parachain-staking/std",
"pallet-proxy-bonding/std",
"pallet-scheduler/std",
"pallet-session/std",
"pallet-skip-feeless-payment/std",
"pallet-staking/std",
"pallet-transaction-payment/std",
"pallet-treasury/std",
Expand All @@ -136,6 +142,7 @@ std = [
"serde/std",
"sp-arithmetic/std",
"sp-authority-discovery/std",
"sp-consensus-aura/std",
"sp-consensus-babe/std",
"sp-consensus-beefy/std",
"sp-core/std",
Expand All @@ -146,10 +153,6 @@ std = [
"xcm-builder/std",
"xcm-executor/std",
"xcm/std",
"pallet-asset-tx-payment/std",
"pallet-aura/std",
"pallet-session/std",
"sp-consensus-aura/std"
]
development-settings = [ "polimec-runtime/development-settings" ]
runtime-benchmarks = [
Expand All @@ -158,6 +161,7 @@ runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"orml-oracle/runtime-benchmarks",
"pallet-asset-tx-payment/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"pallet-collective/runtime-benchmarks",
Expand All @@ -170,7 +174,9 @@ runtime-benchmarks = [
"pallet-membership/runtime-benchmarks",
"pallet-message-queue/runtime-benchmarks",
"pallet-parachain-staking/runtime-benchmarks",
"pallet-proxy-bonding/runtime-benchmarks",
"pallet-scheduler/runtime-benchmarks",
"pallet-skip-feeless-payment/runtime-benchmarks",
"pallet-staking/runtime-benchmarks",
"pallet-treasury/runtime-benchmarks",
"pallet-vesting/runtime-benchmarks",
Expand All @@ -189,6 +195,5 @@ runtime-benchmarks = [
"sp-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks",
"pallet-asset-tx-payment/runtime-benchmarks"
]

7 changes: 5 additions & 2 deletions integration-tests/src/tests/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,12 @@ fn dispenser_signed_extensions_pass_for_new_account() {
frame_system::CheckTxVersion::<PolimecRuntime>::new(),
frame_system::CheckGenesis::<PolimecRuntime>::new(),
frame_system::CheckEra::<PolimecRuntime>::from(Era::mortal(0u64, 0u64)),
pallet_dispenser::extensions::CheckNonce::<PolimecRuntime>::from(0u32),
pallet_dispenser::extensions::CheckNonce::<PolimecRuntime>::from(0),
frame_system::CheckWeight::<PolimecRuntime>::new(),
pallet_asset_tx_payment::ChargeAssetTxPayment::<PolimecRuntime>::from(0u64.into(), None).into(),
pallet_skip_feeless_payment::SkipCheckIfFeeless::<
PolimecRuntime,
pallet_asset_tx_payment::ChargeAssetTxPayment<PolimecRuntime>,
>::from(pallet_asset_tx_payment::ChargeAssetTxPayment::<PolimecRuntime>::from(0u64.into(), None)),
frame_metadata_hash_extension::CheckMetadataHash::<PolimecRuntime>::new(true),
);

Expand Down
19 changes: 9 additions & 10 deletions integration-tests/src/tests/transaction_payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,19 @@ fn fee_paid_with_foreign_assets() {
let paid_call_len = paid_call.encode().len();
type TxPaymentExtension = pallet_asset_tx_payment::ChargeAssetTxPayment<PolimecRuntime>;

// Tips are always defined in the native asset, and then converted to the fee asset if the second field is `Some`.
// Here a user wants to tip 10 PLMC in USDT.
// Tips are always defined in the native asset, and then converted to the fee asset if the second field is `Some`.
// Here a user wants to tip 10 PLMC in USDT.
let signed_extension = pallet_asset_tx_payment::ChargeAssetTxPayment::<PolimecRuntime>::from(
10 * plmc_unit,
Some(usdt_multilocation),
);

let dispatch_info = paid_call.get_dispatch_info();
let FeeDetails { inclusion_fee, tip } =
polimec_runtime::TransactionPayment::compute_fee_details(paid_call_len as u32, &dispatch_info, 10u128 * plmc_unit);
let FeeDetails { inclusion_fee, tip } = polimec_runtime::TransactionPayment::compute_fee_details(
paid_call_len as u32,
&dispatch_info,
10u128 * plmc_unit,
);
let expected_plmc_fee = inclusion_fee.expect("call should charge a fee").inclusion_fee();
let expected_plmc_tip = tip;

Expand Down Expand Up @@ -135,9 +138,7 @@ fn fee_paid_with_foreign_assets() {
post_blockchain_operation_treasury_usdt_balance - prev_blockchain_operation_treasury_usdt_balance,
expected_usd_fee
);
assert_eq!(
post_blockchain_operation_treasury_plmc_balance, prev_blockchain_operation_treasury_plmc_balance
);
assert_eq!(post_blockchain_operation_treasury_plmc_balance, prev_blockchain_operation_treasury_plmc_balance);
assert_eq!(post_block_author_usdt_balance - prev_block_author_usdt_balance, expected_usd_tip);
assert_eq!(post_block_author_plmc_balance, prev_block_author_plmc_balance);

Expand Down Expand Up @@ -177,9 +178,7 @@ fn fee_paid_with_foreign_assets() {

assert_eq!(post_alice_usdt_balance, prev_alice_usdt_balance);
assert_eq!(prev_alice_plmc_balance - post_alice_plmc_balance, expected_plmc_fee + expected_plmc_tip);
assert_eq!(
post_blockchain_operation_treasury_usdt_balance, prev_blockchain_operation_treasury_usdt_balance
);
assert_eq!(post_blockchain_operation_treasury_usdt_balance, prev_blockchain_operation_treasury_usdt_balance);
assert_eq!(
post_blockchain_operation_treasury_plmc_balance - prev_blockchain_operation_treasury_plmc_balance,
expected_plmc_fee
Expand Down
136 changes: 18 additions & 118 deletions pallets/dispenser/src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,10 @@
// If you feel like getting in touch with us, you can do so at [email protected]

use crate::{Call, Config};
use frame_support::{
dispatch::{CheckIfFeeless, DispatchInfo},
pallet_prelude::*,
traits::{IsSubType, OriginTrait},
};
use frame_support::{dispatch::DispatchInfo, pallet_prelude::*, traits::IsSubType};
use parity_scale_codec::{Decode, Encode};
use scale_info::{StaticTypeInfo, TypeInfo};
use sp_runtime::traits::{DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, SignedExtension, Zero};
use scale_info::{TypeInfo};
use sp_runtime::traits::{DispatchInfoOf, Dispatchable, One, SignedExtension, Zero};
use sp_std::vec;
/// Custom CheckNonce signed extension for Polimec Blockchain. Based on the CheckNonce signed extension from the FRAME.
/// Removing the providers and sufficients checks for the `dispense` extrinsic, so a new account
Expand Down Expand Up @@ -75,30 +71,6 @@ where
Ok(())
}

fn pre_dispatch(
self,
who: &Self::AccountId,
call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> Result<(), TransactionValidityError> {
let mut account = frame_system::Account::<T>::get(who);
if account.providers.is_zero() && account.sufficients.is_zero() {
match call.is_sub_type() {
Some(call) if matches!(call, &Call::<T>::dispense { .. }) => {},
_ => return Err(InvalidTransaction::Payment.into()),
}
}
if self.0 != account.nonce {
return Err(
if self.0 < account.nonce { InvalidTransaction::Stale } else { InvalidTransaction::Future }.into()
)
}
account.nonce += T::Nonce::one();
frame_system::Account::<T>::insert(who, account);
Ok(())
}

fn validate(
&self,
who: &Self::AccountId,
Expand All @@ -122,100 +94,28 @@ where

Ok(ValidTransaction { priority: 0, requires, provides, longevity: TransactionLongevity::MAX, propagate: true })
}
}

/// A [`SignedExtension`] that skips the wrapped extension if the dispatchable is feeless.
/// This is an adjusted version of the `CheckIfFeeless` signed extension from FRAME.
/// The FRAME implementation does currently not implement the 'validate' function, which opens
/// up the possibility of DoS attacks. This implementation is a temporary solution until fixed
/// (https://github.com/paritytech/polkadot-sdk/pull/3993) in FRAME.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct SkipCheckIfFeeless<T, S>(pub S, sp_std::marker::PhantomData<T>);

// Make this extension "invisible" from the outside (ie metadata type information)
impl<T, S: StaticTypeInfo> TypeInfo for SkipCheckIfFeeless<T, S> {
type Identity = S;

fn type_info() -> scale_info::Type {
S::type_info()
}
}

impl<T, S: Encode> sp_std::fmt::Debug for SkipCheckIfFeeless<T, S> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "SkipCheckIfFeeless<{:?}>", self.0.encode())
}

#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
Ok(())
}
}

impl<T, S> From<S> for SkipCheckIfFeeless<T, S> {
fn from(s: S) -> Self {
Self(s, sp_std::marker::PhantomData)
}
}

impl<T: Config + Send + Sync, S: SignedExtension<AccountId = T::AccountId>> SignedExtension for SkipCheckIfFeeless<T, S>
where
S::Call: CheckIfFeeless<Origin = frame_system::pallet_prelude::OriginFor<T>>,
{
type AccountId = T::AccountId;
type AdditionalSigned = S::AdditionalSigned;
type Call = S::Call;
type Pre = Option<<S as SignedExtension>::Pre>;

// From the outside this extension should be "invisible", because it just extends the wrapped
// extension with an extra check in `pre_dispatch` and `post_dispatch`. Thus, we should forward
// the identifier of the wrapped extension to let wallets see this extension as it would only be
// the wrapped extension itself.
const IDENTIFIER: &'static str = S::IDENTIFIER;

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

fn pre_dispatch(
self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
if call.is_feeless(&<T as frame_system::Config>::RuntimeOrigin::signed(who.clone())) {
Ok(None)
} else {
Ok(Some(self.0.pre_dispatch(who, call, info, len)?))
}
}

fn validate(
&self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
if call.is_feeless(&<T as frame_system::Config>::RuntimeOrigin::signed(who.clone())) {
Ok(ValidTransaction::default())
} else {
self.0.validate(who, call, info, len)
}
}

fn post_dispatch(
pre: Option<Self::Pre>,
info: &DispatchInfoOf<Self::Call>,
post_info: &PostDispatchInfoOf<Self::Call>,
len: usize,
result: &DispatchResult,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> Result<(), TransactionValidityError> {
if let Some(Some(pre)) = pre {
S::post_dispatch(Some(pre), info, post_info, len, result)?;
let mut account = frame_system::Account::<T>::get(who);
if account.providers.is_zero() && account.sufficients.is_zero() {
match call.is_sub_type() {
Some(call) if matches!(call, &Call::<T>::dispense { .. }) => {},
_ => return Err(InvalidTransaction::Payment.into()),
}
}
if self.0 != account.nonce {
return Err(
if self.0 < account.nonce { InvalidTransaction::Stale } else { InvalidTransaction::Future }.into()
)
}
account.nonce += T::Nonce::one();
frame_system::Account::<T>::insert(who, account);
Ok(())
}
}
5 changes: 2 additions & 3 deletions pallets/dispenser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ pub use frame_support::traits::{
pub use polimec_common::credentials::{Cid, Did, EnsureOriginWithCredentials, InvestorType, UntrustedToken};
pub use sp_runtime::traits::Convert;

pub mod extensions;

#[cfg(test)]
mod mock;

Expand All @@ -42,7 +40,8 @@ mod tests;
pub mod weights;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod benchmarking;
pub mod extensions;

pub type BalanceOf<T> = <CurrencyOf<T> as Currency<AccountIdOf<T>>>::Balance;
pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
Expand Down
4 changes: 4 additions & 0 deletions runtimes/polimec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ sp-version.workspace = true
sp-genesis-builder.workspace = true
frame-metadata-hash-extension.workspace = true
pallet-asset-tx-payment.workspace = true
pallet-skip-feeless-payment.workspace = true

# Polkadot
pallet-xcm.workspace = true
Expand Down Expand Up @@ -159,6 +160,7 @@ std = [
"pallet-proxy/std",
"pallet-scheduler/std",
"pallet-session/std",
"pallet-skip-feeless-payment/std",
"pallet-timestamp/std",
"pallet-transaction-payment-rpc-runtime-api/std",
"pallet-transaction-payment/std",
Expand Down Expand Up @@ -225,6 +227,7 @@ runtime-benchmarks = [
"pallet-proxy-bonding/runtime-benchmarks",
"pallet-proxy/runtime-benchmarks",
"pallet-scheduler/runtime-benchmarks",
"pallet-skip-feeless-payment/runtime-benchmarks",
"pallet-timestamp/runtime-benchmarks",
"pallet-treasury/runtime-benchmarks",
"pallet-utility/runtime-benchmarks",
Expand Down Expand Up @@ -273,6 +276,7 @@ try-runtime = [
"pallet-proxy/try-runtime",
"pallet-scheduler/try-runtime",
"pallet-session/try-runtime",
"pallet-skip-feeless-payment/try-runtime",
"pallet-timestamp/try-runtime",
"pallet-transaction-payment/try-runtime",
"pallet-treasury/try-runtime",
Expand Down
Loading

0 comments on commit 142908c

Please sign in to comment.