Merge branch 'master' of github.com:paritytech/cumulus into release-statemint-v1

This commit is contained in:
Alexander Popiak
2021-10-12 11:30:17 +02:00
21 changed files with 3317 additions and 1461 deletions
Generated
+1965 -1392
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -7,6 +7,7 @@ members = [
"client/network",
"client/pov-recovery",
"client/service",
"pallets/asset-tx-payment",
"pallets/aura-ext",
"pallets/collator-selection",
"pallets/dmp-queue",
+6 -2
View File
@@ -23,8 +23,8 @@ use polkadot_primitives::v1::{
Block as PBlock, BlockNumber, CandidateCommitments, CandidateDescriptor, CandidateEvent,
CommittedCandidateReceipt, CoreState, GroupRotationInfo, Hash as PHash, HeadData, Id as ParaId,
InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, ParachainHost,
PersistedValidationData, SessionIndex, SessionInfo, SigningContext, ValidationCode,
ValidationCodeHash, ValidatorId, ValidatorIndex,
PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, SigningContext,
ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex,
};
use polkadot_test_client::{
Client as PClient, ClientBlockImportExt, DefaultTestClientBuilderExt, FullBackend as PBackend,
@@ -487,5 +487,9 @@ sp_api::mock_impl_runtime_apis! {
fn validation_code_by_hash(_: ValidationCodeHash) -> Option<ValidationCode> {
None
}
fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>> {
None
}
}
}
+51
View File
@@ -0,0 +1,51 @@
[package]
name = "pallet-asset-tx-payment"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "Apache-2.0"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/cumulus/"
description = "pallet to manage transaction payments in assets"
readme = "README.md"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
# Substrate dependencies
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-assets = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
# Other dependencies
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
serde = { version = "1.0.101", optional = true }
[dev-dependencies]
smallvec = "1.4.1"
serde_json = "1.0.41"
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" }
[features]
default = ["std"]
std = [
"serde",
"codec/std",
"sp-std/std",
"sp-runtime/std",
"frame-support/std",
"frame-system/std",
"sp-io/std",
"sp-core/std",
"pallet-transaction-payment/std",
]
try-runtime = ["frame-support/try-runtime"]
+295
View File
@@ -0,0 +1,295 @@
// Copyright (C) 2021 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.
//! # Asset Transaction Payment Pallet
//!
//! This pallet allows runtimes that include it to pay for transactions in assets other than the
//! main token of the chain.
//!
//! ## Overview
//! It does this by extending transactions to include an optional `AssetId` that specifies the asset
//! to be used for payment (defaulting to the native token on `None`). It expects an
//! [`OnChargeAssetTransaction`] implementation analogously to [`pallet-transaction-payment`]. The
//! included [`FungiblesAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the fee
//! amount by converting the fee calculated by [`pallet-transaction-payment`] into the desired
//! asset.
//!
//! ## Integration
//! This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means
//! you should include both pallets in your `construct_runtime` macro, but only include this
//! pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]).
#![cfg_attr(not(feature = "std"), no_std)]
use sp_std::prelude::*;
use codec::{Decode, Encode};
use frame_support::{
dispatch::DispatchResult,
traits::{
tokens::{
fungibles::{Balanced, CreditOf, Inspect},
WithdrawConsequence,
},
IsType,
},
weights::{DispatchInfo, PostDispatchInfo},
DefaultNoBound,
};
use pallet_transaction_payment::OnChargeTransaction;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero},
transaction_validity::{
InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,
},
FixedPointOperand,
};
#[cfg(test)]
mod tests;
mod payment;
pub use payment::*;
// Type aliases used for interaction with `OnChargeTransaction`.
pub(crate) type OnChargeTransactionOf<T> =
<T as pallet_transaction_payment::Config>::OnChargeTransaction;
// Balance type alias.
pub(crate) type BalanceOf<T> = <OnChargeTransactionOf<T> as OnChargeTransaction<T>>::Balance;
// Liquity info type alias.
pub(crate) type LiquidityInfoOf<T> =
<OnChargeTransactionOf<T> as OnChargeTransaction<T>>::LiquidityInfo;
// Type alias used for interaction with fungibles (assets).
// Balance type alias.
pub(crate) type AssetBalanceOf<T> =
<<T as Config>::Fungibles as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
/// Asset id type alias.
pub(crate) type AssetIdOf<T> =
<<T as Config>::Fungibles as Inspect<<T as frame_system::Config>::AccountId>>::AssetId;
// Type aliases used for interaction with `OnChargeAssetTransaction`.
// Balance type alias.
pub(crate) type ChargeAssetBalanceOf<T> =
<<T as Config>::OnChargeAssetTransaction as OnChargeAssetTransaction<T>>::Balance;
// Asset id type alias.
pub(crate) type ChargeAssetIdOf<T> =
<<T as Config>::OnChargeAssetTransaction as OnChargeAssetTransaction<T>>::AssetId;
// Liquity info type alias.
pub(crate) type ChargeAssetLiquidityOf<T> =
<<T as Config>::OnChargeAssetTransaction as OnChargeAssetTransaction<T>>::LiquidityInfo;
/// Used to pass the initial payment info from pre- to post-dispatch.
#[derive(Encode, Decode, DefaultNoBound, TypeInfo)]
pub enum InitialPayment<T: Config> {
/// No initial fee was payed.
Nothing,
/// The initial fee was payed in the native currency.
Native(LiquidityInfoOf<T>),
/// The initial fee was payed in an asset.
Asset(CreditOf<T::AccountId, T::Fungibles>),
}
pub use pallet::*;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
#[pallet::config]
pub trait Config: frame_system::Config + pallet_transaction_payment::Config {
/// The fungibles instance used to pay for transactions in assets.
type Fungibles: Balanced<Self::AccountId>;
/// The actual transaction charging logic that charges the fees.
type OnChargeAssetTransaction: OnChargeAssetTransaction<Self>;
}
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
#[pallet::call]
impl<T: Config> Pallet<T> {}
}
/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
/// in the queue. Allows paying via both `Currency` as well as `fungibles::Balanced`.
///
/// Wraps the transaction logic in [`pallet_transaction_payment`] and extends it with assets.
/// An asset id of `None` falls back to the underlying transaction payment via the native currency.
#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct ChargeAssetTxPayment<T: Config> {
#[codec(compact)]
tip: BalanceOf<T>,
asset_id: Option<ChargeAssetIdOf<T>>,
}
impl<T: Config> ChargeAssetTxPayment<T>
where
T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
AssetBalanceOf<T>: Send + Sync + FixedPointOperand,
BalanceOf<T>: Send + Sync + FixedPointOperand + IsType<ChargeAssetBalanceOf<T>>,
ChargeAssetIdOf<T>: Send + Sync,
CreditOf<T::AccountId, T::Fungibles>: IsType<ChargeAssetLiquidityOf<T>>,
{
/// utility constructor. Used only in client/factory code.
pub fn from(tip: BalanceOf<T>, asset_id: Option<ChargeAssetIdOf<T>>) -> Self {
Self { tip, asset_id }
}
/// Fee withdrawal logic that dispatches to either `OnChargeAssetTransaction` or `OnChargeTransaction`.
fn withdraw_fee(
&self,
who: &T::AccountId,
call: &T::Call,
info: &DispatchInfoOf<T::Call>,
len: usize,
) -> Result<(BalanceOf<T>, InitialPayment<T>), TransactionValidityError> {
let fee = pallet_transaction_payment::Pallet::<T>::compute_fee(len as u32, info, self.tip);
debug_assert!(self.tip <= fee, "tip should be included in the computed fee");
if fee.is_zero() {
Ok((fee, InitialPayment::Nothing))
} else if let Some(asset_id) = self.asset_id {
T::OnChargeAssetTransaction::withdraw_fee(
who,
call,
info,
asset_id,
fee.into(),
self.tip.into(),
)
.map(|i| (fee, InitialPayment::Asset(i.into())))
} else {
<OnChargeTransactionOf<T> as OnChargeTransaction<T>>::withdraw_fee(
who, call, info, fee, self.tip,
)
.map(|i| (fee, InitialPayment::Native(i)))
.map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })
}
}
}
impl<T: Config> sp_std::fmt::Debug for ChargeAssetTxPayment<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "ChargeAssetTxPayment<{:?}, {:?}>", self.tip, self.asset_id.encode())
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
Ok(())
}
}
impl<T: Config> SignedExtension for ChargeAssetTxPayment<T>
where
T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
AssetBalanceOf<T>: Send + Sync + FixedPointOperand,
BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand + IsType<ChargeAssetBalanceOf<T>>,
ChargeAssetIdOf<T>: Send + Sync,
CreditOf<T::AccountId, T::Fungibles>: IsType<ChargeAssetLiquidityOf<T>>,
{
const IDENTIFIER: &'static str = "ChargeAssetTxPayment";
type AccountId = T::AccountId;
type Call = T::Call;
type AdditionalSigned = ();
type Pre = (
// tip
BalanceOf<T>,
// who paid the fee
Self::AccountId,
// imbalance resulting from withdrawing the fee
InitialPayment<T>,
);
fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {
Ok(())
}
fn validate(
&self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
use pallet_transaction_payment::ChargeTransactionPayment;
let (fee, _) = self.withdraw_fee(who, call, info, len)?;
let priority = ChargeTransactionPayment::<T>::get_priority(info, len, self.tip, fee);
Ok(ValidTransaction { priority, ..Default::default() })
}
fn pre_dispatch(
self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?;
Ok((self.tip, who.clone(), initial_payment))
}
fn post_dispatch(
pre: Self::Pre,
info: &DispatchInfoOf<Self::Call>,
post_info: &PostDispatchInfoOf<Self::Call>,
len: usize,
_result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
let (tip, who, initial_payment) = pre;
let actual_fee = pallet_transaction_payment::Pallet::<T>::compute_actual_fee(
len as u32, info, post_info, tip,
);
match initial_payment {
InitialPayment::Native(already_withdrawn) => {
<OnChargeTransactionOf<T> as OnChargeTransaction<T>>::correct_and_deposit_fee(
&who,
info,
post_info,
actual_fee,
tip,
already_withdrawn,
)?;
},
InitialPayment::Asset(already_withdrawn) => {
T::OnChargeAssetTransaction::correct_and_deposit_fee(
&who,
info,
post_info,
actual_fee.into(),
tip.into(),
already_withdrawn.into(),
)?;
},
InitialPayment::Nothing => {
debug_assert!(
actual_fee.is_zero(),
"actual fee should be zero if initial fee was zero."
);
debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero.");
},
}
Ok(())
}
}
+168
View File
@@ -0,0 +1,168 @@
// Copyright (C) 2021 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.
///! Traits and default implementation for paying transaction fees in assets.
use super::*;
use crate::Config;
use codec::FullCodec;
use frame_support::{
traits::{
fungibles::{Balanced, CreditOf, Inspect},
tokens::BalanceConversion,
},
unsigned::TransactionValidityError,
};
use scale_info::TypeInfo;
use sp_runtime::{
traits::{
AtLeast32BitUnsigned, DispatchInfoOf, MaybeSerializeDeserialize, One, PostDispatchInfoOf,
},
transaction_validity::InvalidTransaction,
};
use sp_std::{fmt::Debug, marker::PhantomData};
/// Handle withdrawing, refunding and depositing of transaction fees.
pub trait OnChargeAssetTransaction<T: Config> {
/// The underlying integer type in which fees are calculated.
type Balance: AtLeast32BitUnsigned
+ FullCodec
+ Copy
+ MaybeSerializeDeserialize
+ Debug
+ Default
+ TypeInfo;
/// The type used to identify the assets used for transaction payment.
type AssetId: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo;
/// The type used to store the intermediate values between pre- and post-dispatch.
type LiquidityInfo;
/// Before the transaction is executed the payment of the transaction fees needs to be secured.
///
/// Note: The `fee` already includes the `tip`.
fn withdraw_fee(
who: &T::AccountId,
call: &T::Call,
dispatch_info: &DispatchInfoOf<T::Call>,
asset_id: Self::AssetId,
fee: Self::Balance,
tip: Self::Balance,
) -> Result<Self::LiquidityInfo, TransactionValidityError>;
/// After the transaction was executed the actual fee can be calculated.
/// This function should refund any overpaid fees and optionally deposit
/// the corrected amount.
///
/// Note: The `fee` already includes the `tip`.
fn correct_and_deposit_fee(
who: &T::AccountId,
dispatch_info: &DispatchInfoOf<T::Call>,
post_info: &PostDispatchInfoOf<T::Call>,
corrected_fee: Self::Balance,
tip: Self::Balance,
already_withdrawn: Self::LiquidityInfo,
) -> Result<(), TransactionValidityError>;
}
/// Allows specifying what to do with the withdrawn asset fees.
pub trait HandleCredit<AccountId, B: Balanced<AccountId>> {
/// Implement to determine what to do with the withdrawn asset fees.
/// Default for `CreditOf` from the assets pallet is to burn and
/// decrease total issuance.
fn handle_credit(credit: CreditOf<AccountId, B>);
}
/// Default implementation that just drops the credit according to the `OnDrop` in the underlying
/// imbalance type.
impl<A, B: Balanced<A>> HandleCredit<A, B> for () {
fn handle_credit(_credit: CreditOf<A, B>) {}
}
/// Implements the asset transaction for a balance to asset converter (implementing
/// [`BalanceConversion`]) and a credit handler (implementing [`HandleCredit`]).
///
/// The credit handler is given the complete fee in terms of the asset used for the transaction.
pub struct FungiblesAdapter<CON, HC>(PhantomData<(CON, HC)>);
/// Default implementation for a runtime instantiating this pallet, a balance to asset converter and
/// a credit handler.
impl<T, CON, HC> OnChargeAssetTransaction<T> for FungiblesAdapter<CON, HC>
where
T: Config,
CON: BalanceConversion<BalanceOf<T>, AssetIdOf<T>, AssetBalanceOf<T>>,
HC: HandleCredit<T::AccountId, T::Fungibles>,
AssetIdOf<T>: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo,
{
type Balance = BalanceOf<T>;
type AssetId = AssetIdOf<T>;
type LiquidityInfo = CreditOf<T::AccountId, T::Fungibles>;
/// Withdraw the predicted fee from the transaction origin.
///
/// Note: The `fee` already includes the `tip`.
fn withdraw_fee(
who: &T::AccountId,
_call: &T::Call,
_info: &DispatchInfoOf<T::Call>,
asset_id: Self::AssetId,
fee: Self::Balance,
_tip: Self::Balance,
) -> Result<Self::LiquidityInfo, TransactionValidityError> {
// We don't know the precision of the underlying asset. Because the converted fee could be
// less than one (e.g. 0.5) but gets rounded down by integer division we introduce a minimum
// fee.
let min_converted_fee = if fee.is_zero() { Zero::zero() } else { One::one() };
let converted_fee = CON::to_asset_balance(fee, asset_id)
.map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))?
.max(min_converted_fee);
let can_withdraw = <T::Fungibles as Inspect<T::AccountId>>::can_withdraw(
asset_id.into(),
who,
converted_fee,
);
if !matches!(can_withdraw, WithdrawConsequence::Success) {
return Err(InvalidTransaction::Payment.into())
}
<T::Fungibles as Balanced<T::AccountId>>::withdraw(asset_id.into(), who, converted_fee)
.map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))
}
/// Hand the fee and the tip over to the `[HandleCredit]` implementation.
/// Since the predicted fee might have been too high, parts of the fee may be refunded.
///
/// Note: The `corrected_fee` already includes the `tip`.
fn correct_and_deposit_fee(
who: &T::AccountId,
_dispatch_info: &DispatchInfoOf<T::Call>,
_post_info: &PostDispatchInfoOf<T::Call>,
corrected_fee: Self::Balance,
_tip: Self::Balance,
paid: Self::LiquidityInfo,
) -> Result<(), TransactionValidityError> {
let min_converted_fee = if corrected_fee.is_zero() { Zero::zero() } else { One::one() };
// Convert the corrected fee into the asset used for payment.
let converted_fee = CON::to_asset_balance(corrected_fee, paid.asset().into())
.map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })?
.max(min_converted_fee);
// Calculate how much refund we should return.
let (final_fee, refund) = paid.split(converted_fee);
// Refund to the account that paid the fees. If this fails, the account might have dropped
// below the existential balance. In that case we don't refund anything.
let _ = <T::Fungibles as Balanced<T::AccountId>>::resolve(who, refund);
// Handle the final fee, e.g. by transferring to the block author or burning.
HC::handle_credit(final_fee);
Ok(())
}
}
+636
View File
@@ -0,0 +1,636 @@
// Copyright (C) 2021 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.
use super::*;
use crate as pallet_asset_tx_payment;
use frame_support::{
assert_ok,
pallet_prelude::*,
parameter_types,
traits::{fungibles::Mutate, FindAuthor},
weights::{
DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFeeCoefficient,
WeightToFeeCoefficients, WeightToFeePolynomial,
},
ConsensusEngineId,
};
use frame_system as system;
use frame_system::EnsureRoot;
use pallet_balances::Call as BalancesCall;
use pallet_transaction_payment::CurrencyAdapter;
use smallvec::smallvec;
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, ConvertInto, IdentityLookup, StaticLookup},
Perbill,
};
use std::cell::RefCell;
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
type Block = frame_system::mocking::MockBlock<Runtime>;
type Balance = u64;
type AccountId = u64;
frame_support::construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: system::{Pallet, Call, Config, Storage, Event<T>},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
Assets: pallet_assets::{Pallet, Call, Storage, Event<T>},
Authorship: pallet_authorship::{Pallet, Call, Storage},
AssetTxPayment: pallet_asset_tx_payment::{Pallet},
}
);
const CALL: &<Runtime as frame_system::Config>::Call =
&Call::Balances(BalancesCall::transfer { dest: 2, value: 69 });
thread_local! {
static EXTRINSIC_BASE_WEIGHT: RefCell<u64> = RefCell::new(0);
}
pub struct BlockWeights;
impl Get<frame_system::limits::BlockWeights> for BlockWeights {
fn get() -> frame_system::limits::BlockWeights {
frame_system::limits::BlockWeights::builder()
.base_block(0)
.for_class(DispatchClass::all(), |weights| {
weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into();
})
.for_class(DispatchClass::non_mandatory(), |weights| {
weights.max_total = 1024.into();
})
.build_or_panic()
}
}
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub static TransactionByteFee: u64 = 1;
pub static WeightToFee: u64 = 1;
}
impl frame_system::Config for Runtime {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = BlockWeights;
type BlockLength = ();
type DbWeight = ();
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Call = Call;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type BlockHashCount = BlockHashCount;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
}
parameter_types! {
pub const ExistentialDeposit: u64 = 10;
pub const MaxReserves: u32 = 50;
}
impl pallet_balances::Config for Runtime {
type Balance = Balance;
type Event = Event;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type MaxLocks = ();
type WeightInfo = ();
type MaxReserves = MaxReserves;
type ReserveIdentifier = [u8; 8];
}
impl WeightToFeePolynomial for WeightToFee {
type Balance = u64;
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
smallvec![WeightToFeeCoefficient {
degree: 1,
coeff_frac: Perbill::zero(),
coeff_integer: WEIGHT_TO_FEE.with(|v| *v.borrow()),
negative: false,
}]
}
}
parameter_types! {
pub const OperationalFeeMultiplier: u8 = 5;
}
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = CurrencyAdapter<Balances, ()>;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = WeightToFee;
type FeeMultiplierUpdate = ();
type OperationalFeeMultiplier = OperationalFeeMultiplier;
}
parameter_types! {
pub const AssetDeposit: u64 = 2;
pub const MetadataDeposit: u64 = 0;
pub const StringLimit: u32 = 20;
}
impl pallet_assets::Config for Runtime {
type Event = Event;
type Balance = Balance;
type AssetId = u32;
type Currency = Balances;
type ForceOrigin = EnsureRoot<AccountId>;
type AssetDeposit = AssetDeposit;
type MetadataDepositBase = MetadataDeposit;
type MetadataDepositPerByte = MetadataDeposit;
type ApprovalDeposit = MetadataDeposit;
type StringLimit = StringLimit;
type Freezer = ();
type Extra = ();
type WeightInfo = ();
}
pub struct HardcodedAuthor;
const BLOCK_AUTHOR: AccountId = 1234;
impl FindAuthor<AccountId> for HardcodedAuthor {
fn find_author<'a, I>(_: I) -> Option<AccountId>
where
I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
{
Some(BLOCK_AUTHOR)
}
}
impl pallet_authorship::Config for Runtime {
type FindAuthor = HardcodedAuthor;
type UncleGenerations = ();
type FilterUncle = ();
type EventHandler = ();
}
pub struct CreditToBlockAuthor;
impl HandleCredit<AccountId, Assets> for CreditToBlockAuthor {
fn handle_credit(credit: CreditOf<AccountId, Assets>) {
let author = pallet_authorship::Pallet::<Runtime>::author();
// TODO: what to do in case paying the author fails (e.g. because `fee < min_balance`)
// default: drop the result which will trigger the `OnDrop` of the imbalance.
let _ = <Assets as Balanced<AccountId>>::resolve(&author, credit);
}
}
impl Config for Runtime {
type Fungibles = Assets;
type OnChargeAssetTransaction = FungiblesAdapter<
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
CreditToBlockAuthor,
>;
}
pub struct ExtBuilder {
balance_factor: u64,
base_weight: u64,
byte_fee: u64,
weight_to_fee: u64,
}
impl Default for ExtBuilder {
fn default() -> Self {
Self { balance_factor: 1, base_weight: 0, byte_fee: 1, weight_to_fee: 1 }
}
}
impl ExtBuilder {
pub fn base_weight(mut self, base_weight: u64) -> Self {
self.base_weight = base_weight;
self
}
pub fn balance_factor(mut self, factor: u64) -> Self {
self.balance_factor = factor;
self
}
fn set_constants(&self) {
EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight);
TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee);
WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee);
}
pub fn build(self) -> sp_io::TestExternalities {
self.set_constants();
let mut t = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
pallet_balances::GenesisConfig::<Runtime> {
balances: if self.balance_factor > 0 {
vec![
(1, 10 * self.balance_factor),
(2, 20 * self.balance_factor),
(3, 30 * self.balance_factor),
(4, 40 * self.balance_factor),
(5, 50 * self.balance_factor),
(6, 60 * self.balance_factor),
]
} else {
vec![]
},
}
.assimilate_storage(&mut t)
.unwrap();
t.into()
}
}
/// create a transaction info struct from weight. Handy to avoid building the whole struct.
pub fn info_from_weight(w: Weight) -> DispatchInfo {
// pays_fee: Pays::Yes -- class: DispatchClass::Normal
DispatchInfo { weight: w, ..Default::default() }
}
fn post_info_from_weight(w: Weight) -> PostDispatchInfo {
PostDispatchInfo { actual_weight: Some(w), pays_fee: Default::default() }
}
fn info_from_pays(p: Pays) -> DispatchInfo {
DispatchInfo { pays_fee: p, ..Default::default() }
}
fn post_info_from_pays(p: Pays) -> PostDispatchInfo {
PostDispatchInfo { actual_weight: None, pays_fee: p }
}
fn default_post_info() -> PostDispatchInfo {
PostDispatchInfo { actual_weight: None, pays_fee: Default::default() }
}
#[test]
fn transaction_payment_in_native_possible() {
let balance_factor = 100;
ExtBuilder::default()
.balance_factor(balance_factor)
.base_weight(5)
.build()
.execute_with(|| {
let len = 10;
let pre = ChargeAssetTxPayment::<Runtime>::from(0, None)
.pre_dispatch(&1, CALL, &info_from_weight(5), len)
.unwrap();
let initial_balance = 10 * balance_factor;
assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10);
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
pre,
&info_from_weight(5),
&default_post_info(),
len,
&Ok(())
));
assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10);
let pre = ChargeAssetTxPayment::<Runtime>::from(5 /* tipped */, None)
.pre_dispatch(&2, CALL, &info_from_weight(100), len)
.unwrap();
let initial_balance_for_2 = 20 * balance_factor;
assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5);
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
pre,
&info_from_weight(100),
&post_info_from_weight(50),
len,
&Ok(())
));
assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5);
});
}
#[test]
fn transaction_payment_in_asset_possible() {
let base_weight = 5;
let balance_factor = 100;
ExtBuilder::default()
.balance_factor(balance_factor)
.base_weight(base_weight)
.build()
.execute_with(|| {
// create the asset
let asset_id = 1;
let min_balance = 2;
assert_ok!(Assets::force_create(
Origin::root(),
asset_id,
42, /* owner */
true, /* is_sufficient */
min_balance
));
// mint into the caller account
let caller = 1;
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
let balance = 100;
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
assert_eq!(Assets::balance(asset_id, caller), balance);
let weight = 5;
let len = 10;
// we convert the from weight to fee based on the ratio between asset min balance and
// existential deposit
let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get();
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
.unwrap();
// assert that native balance is not used
assert_eq!(Balances::free_balance(caller), 10 * balance_factor);
// check that fee was charged in the given asset
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0);
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
pre,
&info_from_weight(weight),
&default_post_info(),
len,
&Ok(())
));
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
// check that the block author gets rewarded
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), fee);
});
}
#[test]
fn transaction_payment_without_fee() {
let base_weight = 5;
let balance_factor = 100;
ExtBuilder::default()
.balance_factor(balance_factor)
.base_weight(base_weight)
.build()
.execute_with(|| {
// create the asset
let asset_id = 1;
let min_balance = 2;
assert_ok!(Assets::force_create(
Origin::root(),
asset_id,
42, /* owner */
true, /* is_sufficient */
min_balance
));
// mint into the caller account
let caller = 1;
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
let balance = 100;
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
assert_eq!(Assets::balance(asset_id, caller), balance);
let weight = 5;
let len = 10;
// we convert the from weight to fee based on the ratio between asset min balance and
// existential deposit
let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get();
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
.unwrap();
// assert that native balance is not used
assert_eq!(Balances::free_balance(caller), 10 * balance_factor);
// check that fee was charged in the given asset
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0);
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
pre,
&info_from_weight(weight),
&post_info_from_pays(Pays::No),
len,
&Ok(())
));
// caller should be refunded
assert_eq!(Assets::balance(asset_id, caller), balance);
// check that the block author did not get rewarded
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0);
});
}
#[test]
fn asset_transaction_payment_with_tip_and_refund() {
let base_weight = 5;
ExtBuilder::default()
.balance_factor(100)
.base_weight(base_weight)
.build()
.execute_with(|| {
// create the asset
let asset_id = 1;
let min_balance = 2;
assert_ok!(Assets::force_create(
Origin::root(),
asset_id,
42, /* owner */
true, /* is_sufficient */
min_balance
));
// mint into the caller account
let caller = 2;
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
let balance = 1000;
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
assert_eq!(Assets::balance(asset_id, caller), balance);
let weight = 100;
let tip = 5;
let len = 10;
// we convert the from weight to fee based on the ratio between asset min balance and
// existential deposit
let fee_with_tip =
(base_weight + weight + len as u64 + tip) * min_balance / ExistentialDeposit::get();
let pre = ChargeAssetTxPayment::<Runtime>::from(tip, Some(asset_id))
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
.unwrap();
assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip);
let final_weight = 50;
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
pre,
&info_from_weight(weight),
&post_info_from_weight(final_weight),
len,
&Ok(())
));
let final_fee =
fee_with_tip - (weight - final_weight) * min_balance / ExistentialDeposit::get();
assert_eq!(Assets::balance(asset_id, caller), balance - (final_fee));
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), final_fee);
});
}
#[test]
fn payment_from_account_with_only_assets() {
let base_weight = 5;
ExtBuilder::default()
.balance_factor(100)
.base_weight(base_weight)
.build()
.execute_with(|| {
// create the asset
let asset_id = 1;
let min_balance = 2;
assert_ok!(Assets::force_create(
Origin::root(),
asset_id,
42, /* owner */
true, /* is_sufficient */
min_balance
));
// mint into the caller account
let caller = 333;
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
let balance = 100;
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
assert_eq!(Assets::balance(asset_id, caller), balance);
// assert that native balance is not necessary
assert_eq!(Balances::free_balance(caller), 0);
let weight = 5;
let len = 10;
// we convert the from weight to fee based on the ratio between asset min balance and
// existential deposit
let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get();
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
.unwrap();
assert_eq!(Balances::free_balance(caller), 0);
// check that fee was charged in the given asset
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
pre,
&info_from_weight(weight),
&default_post_info(),
len,
&Ok(())
));
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
assert_eq!(Balances::free_balance(caller), 0);
});
}
#[test]
fn payment_only_with_existing_sufficient_asset() {
let base_weight = 5;
ExtBuilder::default()
.balance_factor(100)
.base_weight(base_weight)
.build()
.execute_with(|| {
let asset_id = 1;
let caller = 1;
let weight = 5;
let len = 10;
// pre_dispatch fails for non-existent asset
assert!(ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
.is_err());
// create the non-sufficient asset
let min_balance = 2;
assert_ok!(Assets::force_create(
Origin::root(),
asset_id,
42, /* owner */
false, /* is_sufficient */
min_balance
));
// pre_dispatch fails for non-sufficient asset
assert!(ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
.is_err());
});
}
#[test]
fn converted_fee_is_never_zero_if_input_fee_is_not() {
let base_weight = 1;
ExtBuilder::default()
.balance_factor(100)
.base_weight(base_weight)
.build()
.execute_with(|| {
// create the asset
let asset_id = 1;
let min_balance = 1;
assert_ok!(Assets::force_create(
Origin::root(),
asset_id,
42, /* owner */
true, /* is_sufficient */
min_balance
));
// mint into the caller account
let caller = 333;
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
let balance = 100;
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
assert_eq!(Assets::balance(asset_id, caller), balance);
let weight = 1;
let len = 1;
// we convert the from weight to fee based on the ratio between asset min balance and
// existential deposit
let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get();
// naive fee calculation would round down to zero
assert_eq!(fee, 0);
{
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
.pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len)
.unwrap();
// `Pays::No` still implies no fees
assert_eq!(Assets::balance(asset_id, caller), balance);
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
pre,
&info_from_pays(Pays::No),
&post_info_from_pays(Pays::No),
len,
&Ok(())
));
assert_eq!(Assets::balance(asset_id, caller), balance);
}
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
.unwrap();
// check that at least one coin was charged in the given asset
assert_eq!(Assets::balance(asset_id, caller), balance - 1);
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
pre,
&info_from_weight(weight),
&default_post_info(),
len,
&Ok(())
));
assert_eq!(Assets::balance(asset_id, caller), balance - 1);
});
}
+3
View File
@@ -15,8 +15,10 @@ targets = ['x86_64-unknown-linux-gnu']
[dependencies]
log = { version = "0.4.0", default-features = false }
codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '2.3.0' }
rand = { version = "0.7.2", default-features = false }
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
serde = { version = "1.0.119", default-features = false }
sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11" }
sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11" }
sp-staking = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11" }
@@ -48,6 +50,7 @@ std = [
'codec/std',
'log/std',
'scale-info/std',
'rand/std',
'sp-runtime/std',
'sp-staking/std',
'sp-std/std',
+74 -7
View File
@@ -22,11 +22,12 @@ use crate::Pallet as CollatorSelection;
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};
use frame_support::{
assert_ok,
codec::Decode,
traits::{Currency, EnsureOrigin, Get},
};
use frame_system::{EventRecord, RawOrigin};
use pallet_authorship::EventHandler;
use pallet_session::SessionManager;
use pallet_session::{self as session, SessionManager};
use sp_std::prelude::*;
pub type BalanceOf<T> =
@@ -51,9 +52,50 @@ fn assert_last_event<T: Config>(generic_event: <T as Config>::Event) {
assert_eq!(event, &system_event);
}
fn create_funded_user<T: Config>(
string: &'static str,
n: u32,
balance_factor: u32,
) -> T::AccountId {
let user = account(string, n, SEED);
let balance = T::Currency::minimum_balance() * balance_factor.into();
let _ = T::Currency::make_free_balance_be(&user, balance);
user
}
fn keys<T: Config + session::Config>(c: u32) -> <T as session::Config>::Keys {
use rand::{RngCore, SeedableRng};
let keys = {
let mut keys = [0u8; 128];
if c > 0 {
let mut rng = rand::rngs::StdRng::seed_from_u64(c as u64);
rng.fill_bytes(&mut keys);
}
keys
};
Decode::decode(&mut &keys[..]).unwrap()
}
fn validator<T: Config + session::Config>(c: u32) -> (T::AccountId, <T as session::Config>::Keys) {
(create_funded_user::<T>("candidate", c, 1000), keys::<T>(c))
}
fn register_validators<T: Config + session::Config>(count: u32) {
let validators = (0..count).map(|c| validator::<T>(c)).collect::<Vec<_>>();
for (who, keys) in validators {
<session::Module<T>>::set_keys(RawOrigin::Signed(who).into(), keys, vec![]).unwrap();
}
}
fn register_candidates<T: Config>(count: u32) {
let candidates = (0..count).map(|c| account("candidate", c, SEED)).collect::<Vec<_>>();
assert!(<CandidacyBond<T>>::get() > 0u32.into(), "Bond cannot be zero!");
for who in candidates {
T::Currency::make_free_balance_be(&who, <CandidacyBond<T>>::get() * 2u32.into());
<CollatorSelection<T>>::register_as_candidate(RawOrigin::Signed(who).into()).unwrap();
@@ -61,7 +103,7 @@ fn register_candidates<T: Config>(count: u32) {
}
benchmarks! {
where_clause { where T: pallet_authorship::Config }
where_clause { where T: pallet_authorship::Config + session::Config }
set_invulnerables {
let b in 1 .. T::MaxInvulnerables::get();
@@ -107,12 +149,20 @@ benchmarks! {
<CandidacyBond<T>>::put(T::Currency::minimum_balance());
<DesiredCandidates<T>>::put(c + 1);
register_validators::<T>(c);
register_candidates::<T>(c);
let caller: T::AccountId = whitelisted_caller();
let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into();
T::Currency::make_free_balance_be(&caller, bond.clone());
<session::Module<T>>::set_keys(
RawOrigin::Signed(caller.clone()).into(),
keys::<T>(c + 1),
vec![]
).unwrap();
}: _(RawOrigin::Signed(caller.clone()))
verify {
assert_last_event::<T>(Event::CandidateAdded(caller, bond / 2u32.into()).into());
@@ -120,9 +170,11 @@ benchmarks! {
// worse case is the last candidate leaving.
leave_intent {
let c in 1 .. T::MaxCandidates::get();
let c in (T::MinCandidates::get() + 1) .. T::MaxCandidates::get();
<CandidacyBond<T>>::put(T::Currency::minimum_balance());
<DesiredCandidates<T>>::put(c);
register_validators::<T>(c);
register_candidates::<T>(c);
let leaving = <Candidates<T>>::get().last().unwrap().who.clone();
@@ -160,6 +212,8 @@ benchmarks! {
<CandidacyBond<T>>::put(T::Currency::minimum_balance());
<DesiredCandidates<T>>::put(c);
frame_system::Pallet::<T>::set_block_number(0u32.into());
register_validators::<T>(c);
register_candidates::<T>(c);
let new_block: T::BlockNumber = 1800u32.into();
@@ -171,19 +225,32 @@ benchmarks! {
for i in 0..c {
<LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), zero_block);
}
for i in 0..non_removals {
<LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), new_block);
if non_removals > 0 {
for i in 0..non_removals {
<LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), new_block);
}
} else {
for i in 0..c {
<LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), new_block);
}
}
let pre_length = <Candidates<T>>::get().len();
frame_system::Pallet::<T>::set_block_number(new_block);
assert!(<Candidates<T>>::get().len() == c as usize);
}: {
<CollatorSelection<T> as SessionManager<_>>::new_session(0)
} verify {
assert!(<Candidates<T>>::get().len() < pre_length);
if c > r && non_removals >= T::MinCandidates::get() {
assert!(<Candidates<T>>::get().len() < pre_length);
} else if c > r && non_removals < T::MinCandidates::get() {
assert!(<Candidates<T>>::get().len() == T::MinCandidates::get() as usize);
} else {
assert!(<Candidates<T>>::get().len() == pre_length);
}
}
}
+1 -2
View File
@@ -161,7 +161,7 @@ impl pallet_session::SessionHandler<u64> for TestSessionHandler {
SessionHandlerCollators::set(keys.into_iter().map(|(a, _)| *a).collect::<Vec<_>>())
}
fn on_before_session_ending() {}
fn on_disabled(_: usize) {}
fn on_disabled(_: u32) {}
}
parameter_types! {
@@ -179,7 +179,6 @@ impl pallet_session::Config for Test {
type SessionManager = CollatorSelection;
type SessionHandler = TestSessionHandler;
type Keys = MockSessionKeys;
type DisabledValidatorsThreshold = ();
type WeightInfo = ();
}
-2
View File
@@ -545,7 +545,6 @@ impl cumulus_pallet_dmp_queue::Config for Runtime {
}
parameter_types! {
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33);
pub const Period: u32 = 6 * HOURS;
pub const Offset: u32 = 0;
pub const MaxAuthorities: u32 = 100_000;
@@ -562,7 +561,6 @@ impl pallet_session::Config for Runtime {
// Essentially just Aura, but lets be pedantic.
type SessionHandler = <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = ();
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "polkadot-collator"
version = "0.1.0"
version = "4.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
edition = "2018"
@@ -20,6 +20,8 @@ sp-io = { git = 'https://github.com/paritytech/substrate', default-features = fa
frame-executive = { git = 'https://github.com/paritytech/substrate', default-features = false , branch = "polkadot-v0.9.11" }
frame-support = { git = 'https://github.com/paritytech/substrate', default-features = false , branch = "polkadot-v0.9.11" }
frame-system = { git = 'https://github.com/paritytech/substrate', default-features = false , branch = "polkadot-v0.9.11" }
pallet-assets = { git = 'https://github.com/paritytech/substrate', default-features = false , branch = "polkadot-v0.9.11" }
pallet-authorship = { git = 'https://github.com/paritytech/substrate', default-features = false , branch = "polkadot-v0.9.11" }
pallet-balances = { git = 'https://github.com/paritytech/substrate', default-features = false , branch = "polkadot-v0.9.11" }
sp-runtime = { git = 'https://github.com/paritytech/substrate', default-features = false , branch = "polkadot-v0.9.11" }
sp-core = { git = 'https://github.com/paritytech/substrate', default-features = false , branch = "polkadot-v0.9.11" }
@@ -32,6 +34,7 @@ xcm = { git = 'https://github.com/paritytech/polkadot', default-features = false
xcm-executor = { git = 'https://github.com/paritytech/polkadot', default-features = false , branch = "release-v0.9.11" }
# Local dependencies
pallet-asset-tx-payment = { path = '../../pallets/asset-tx-payment', default-features = false }
pallet-collator-selection = { path = '../../pallets/collator-selection', default-features = false }
[dev-dependencies]
@@ -52,7 +55,10 @@ std = [
'frame-support/std',
'frame-executive/std',
'frame-system/std',
'pallet-asset-tx-payment/std',
'pallet-collator-selection/std',
'pallet-assets/std',
'pallet-authorship/std',
'pallet-balances/std',
'node-primitives/std',
'polkadot-runtime-common/std',
@@ -16,23 +16,31 @@
//! Auxillary struct/enums for parachain runtimes.
//! Taken from polkadot/runtime/common (at a21cd64) and adapted for parachains.
use frame_support::traits::{fungibles, Contains, Currency, Get, Imbalance, OnUnbalanced};
use frame_support::traits::{
fungibles::{self, Balanced, CreditOf},
Contains, Currency, Get, Imbalance, OnUnbalanced,
};
use pallet_asset_tx_payment::HandleCredit;
use sp_runtime::traits::Zero;
use sp_std::marker::PhantomData;
use xcm::latest::{AssetId, Fungibility::Fungible, MultiAsset, MultiLocation};
use xcm_executor::traits::FilterAssetLocation;
/// Type alias to conveniently refer to the `Currency::NegativeImbalance` associated type.
pub type NegativeImbalance<T> = <pallet_balances::Pallet<T> as Currency<
<T as frame_system::Config>::AccountId,
>>::NegativeImbalance;
/// Logic for the author to get a portion of fees.
pub struct ToStakingPot<R>(sp_std::marker::PhantomData<R>);
/// Type alias to conveniently refer to `frame_system`'s `Config::AccountId`.
pub type AccountIdOf<R> = <R as frame_system::Config>::AccountId;
/// Implementation of `OnUnbalanced` that deposits the fees into a staking pot for later payout.
pub struct ToStakingPot<R>(PhantomData<R>);
impl<R> OnUnbalanced<NegativeImbalance<R>> for ToStakingPot<R>
where
R: pallet_balances::Config + pallet_collator_selection::Config,
<R as frame_system::Config>::AccountId: From<polkadot_primitives::v1::AccountId>,
<R as frame_system::Config>::AccountId: Into<polkadot_primitives::v1::AccountId>,
AccountIdOf<R>:
From<polkadot_primitives::v1::AccountId> + Into<polkadot_primitives::v1::AccountId>,
<R as frame_system::Config>::Event: From<pallet_balances::Event<R>>,
{
fn on_nonzero_unbalanced(amount: NegativeImbalance<R>) {
@@ -46,13 +54,14 @@ where
}
}
/// Merge the fees into one item and pass them on to the staking pot.
pub struct DealWithFees<R>(sp_std::marker::PhantomData<R>);
/// Implementation of `OnUnbalanced` that deals with the fees by combining tip and fee and passing
/// the result on to `ToStakingPot`.
pub struct DealWithFees<R>(PhantomData<R>);
impl<R> OnUnbalanced<NegativeImbalance<R>> for DealWithFees<R>
where
R: pallet_balances::Config + pallet_collator_selection::Config,
<R as frame_system::Config>::AccountId: From<polkadot_primitives::v1::AccountId>,
<R as frame_system::Config>::AccountId: Into<polkadot_primitives::v1::AccountId>,
AccountIdOf<R>:
From<polkadot_primitives::v1::AccountId> + Into<polkadot_primitives::v1::AccountId>,
<R as frame_system::Config>::Event: From<pallet_balances::Event<R>>,
{
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance<R>>) {
@@ -65,6 +74,22 @@ where
}
}
/// A `HandleCredit` implementation that naively transfers the fees to the block author.
/// Will drop and burn the assets in case the transfer fails.
pub struct AssetsToBlockAuthor<R>(PhantomData<R>);
impl<R> HandleCredit<AccountIdOf<R>, pallet_assets::Pallet<R>> for AssetsToBlockAuthor<R>
where
R: pallet_authorship::Config + pallet_assets::Config,
AccountIdOf<R>:
From<polkadot_primitives::v1::AccountId> + Into<polkadot_primitives::v1::AccountId>,
{
fn handle_credit(credit: CreditOf<AccountIdOf<R>, pallet_assets::Pallet<R>>) {
let author = pallet_authorship::Pallet::<R>::author();
// In case of error: Will drop the result triggering the `OnDrop` of the imbalance.
let _ = pallet_assets::Pallet::<R>::resolve(&author, credit);
}
}
/// Allow checking in assets that have issuance > 0.
pub struct NonZeroIssuance<AccountId, Assets>(PhantomData<(AccountId, Assets)>);
impl<AccountId, Assets> Contains<<Assets as fungibles::Inspect<AccountId>>::AssetId>
+2
View File
@@ -62,6 +62,7 @@ cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-feature
cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false }
cumulus-pallet-session-benchmarking = {path = "../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
cumulus-ping = { path = "../pallets/ping", default-features = false }
pallet-asset-tx-payment = { path = "../../pallets/asset-tx-payment", default-features = false }
pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false }
parachains-common = { path = "../parachains-common", default-features = false }
@@ -136,6 +137,7 @@ std = [
"pallet-utility/std",
"parachain-info/std",
"cumulus-pallet-aura-ext/std",
"pallet-asset-tx-payment/std",
"pallet-collator-selection/std",
"cumulus-pallet-dmp-queue/std",
"cumulus-pallet-parachain-system/std",
+16 -18
View File
@@ -29,9 +29,9 @@ use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT},
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, Perbill,
ApplyExtrinsicResult,
};
use sp_std::prelude::*;
@@ -56,7 +56,7 @@ use frame_system::{
};
pub use parachains_common as common;
use parachains_common::{
impls::{DealWithFees, NonZeroIssuance},
impls::{AssetsToBlockAuthor, DealWithFees, NonZeroIssuance},
opaque, AccountId, AssetId, AuraId, Balance, BlockNumber, Hash, Header, Index, Signature,
AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION,
};
@@ -90,10 +90,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("statemine"),
impl_name: create_runtime_str!("statemine"),
authoring_version: 1,
spec_version: 3,
spec_version: 5,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
transaction_version: 3,
};
/// The version information used to identify this runtime when compiled natively.
@@ -637,7 +637,6 @@ impl cumulus_pallet_dmp_queue::Config for Runtime {
}
parameter_types! {
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33);
pub const Period: u32 = 6 * HOURS;
pub const Offset: u32 = 0;
pub const MaxAuthorities: u32 = 100_000;
@@ -654,7 +653,6 @@ impl pallet_session::Config for Runtime {
// Essentially just Aura, but lets be pedantic.
type SessionHandler = <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = weights::pallet_session::WeightInfo<Runtime>;
}
@@ -695,6 +693,14 @@ impl pallet_collator_selection::Config for Runtime {
type WeightInfo = weights::pallet_collator_selection::WeightInfo<Runtime>;
}
impl pallet_asset_tx_payment::Config for Runtime {
type Fungibles = Assets;
type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter<
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
AssetsToBlockAuthor<Runtime>,
>;
}
// Create the runtime by composing the FRAME pallets that were previously configured.
construct_runtime!(
pub enum Runtime where
@@ -714,6 +720,7 @@ construct_runtime!(
// Monetary stuff.
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 10,
TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 11,
AssetTxPayment: pallet_asset_tx_payment::{Pallet} = 12,
// Collator support. the order of these 4 are important and shall not change.
Authorship: pallet_authorship::{Pallet, Call, Storage} = 20,
@@ -755,7 +762,7 @@ pub type SignedExtra = (
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
pallet_asset_tx_payment::ChargeAssetTxPayment<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
@@ -768,18 +775,9 @@ pub type Executive = frame_executive::Executive<
frame_system::ChainContext<Runtime>,
Runtime,
AllPallets,
OnRuntimeUpgrade,
(),
>;
pub struct OnRuntimeUpgrade;
impl frame_support::traits::OnRuntimeUpgrade for OnRuntimeUpgrade {
fn on_runtime_upgrade() -> u64 {
frame_support::migrations::migrate_from_pallet_version_to_storage_version::<
AllPalletsWithSystem,
>(&RocksDbWeight::get())
}
}
impl_runtime_apis! {
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> sp_consensus_aura::SlotDuration {
+2
View File
@@ -62,6 +62,7 @@ cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-feature
cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false }
cumulus-pallet-session-benchmarking = { path = "../../pallets/session-benchmarking", default-features = false, version = "3.0.0" }
cumulus-ping = { path = "../pallets/ping", default-features = false }
pallet-asset-tx-payment = { path = "../../pallets/asset-tx-payment", default-features = false }
pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false }
parachains-common = { path = "../parachains-common", default-features = false }
@@ -136,6 +137,7 @@ std = [
"pallet-utility/std",
"parachain-info/std",
"cumulus-pallet-aura-ext/std",
"pallet-asset-tx-payment/std",
"pallet-collator-selection/std",
"cumulus-pallet-dmp-queue/std",
"cumulus-pallet-parachain-system/std",
+15 -8
View File
@@ -29,9 +29,9 @@ use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT},
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, Perbill,
ApplyExtrinsicResult,
};
use sp_std::prelude::*;
@@ -56,7 +56,7 @@ use frame_system::{
};
pub use parachains_common as common;
use parachains_common::{
impls::{DealWithFees, NonZeroIssuance},
impls::{AssetsToBlockAuthor, DealWithFees, NonZeroIssuance},
opaque, AccountId, AssetId, AuraId, Balance, BlockNumber, Hash, Header, Index, Signature,
AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION,
};
@@ -90,10 +90,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("statemint"),
impl_name: create_runtime_str!("statemint"),
authoring_version: 1,
spec_version: 1,
spec_version: 2,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
transaction_version: 2,
};
/// The version information used to identify this runtime when compiled natively.
@@ -600,7 +600,6 @@ impl cumulus_pallet_dmp_queue::Config for Runtime {
}
parameter_types! {
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33);
pub const Period: u32 = 6 * HOURS;
pub const Offset: u32 = 0;
pub const MaxAuthorities: u32 = 100_000;
@@ -617,7 +616,6 @@ impl pallet_session::Config for Runtime {
// Essentially just Aura, but lets be pedantic.
type SessionHandler = <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = weights::pallet_session::WeightInfo<Runtime>;
}
@@ -658,6 +656,14 @@ impl pallet_collator_selection::Config for Runtime {
type WeightInfo = weights::pallet_collator_selection::WeightInfo<Runtime>;
}
impl pallet_asset_tx_payment::Config for Runtime {
type Fungibles = Assets;
type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter<
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
AssetsToBlockAuthor<Runtime>,
>;
}
parameter_types! {
pub const ClassDeposit: Balance = UNITS; // 1 UNIT deposit to create asset class
pub const InstanceDeposit: Balance = UNITS / 100; // 1/100 UNIT deposit to create asset instance
@@ -705,6 +711,7 @@ construct_runtime!(
// Monetary stuff.
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 10,
TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 11,
AssetTxPayment: pallet_asset_tx_payment::{Pallet} = 12,
// Collator support. the order of these 4 are important and shall not change.
Authorship: pallet_authorship::{Pallet, Call, Storage} = 20,
@@ -746,7 +753,7 @@ pub type SignedExtra = (
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
pallet_asset_tx_payment::ChargeAssetTxPayment<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
+2
View File
@@ -62,6 +62,7 @@ cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-feature
cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false }
cumulus-pallet-session-benchmarking = {path = "../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
cumulus-ping = { path = "../pallets/ping", default-features = false }
pallet-asset-tx-payment = { path = "../../pallets/asset-tx-payment", default-features = false }
pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false }
parachains-common = { path = "../parachains-common", default-features = false }
@@ -136,6 +137,7 @@ std = [
"pallet-utility/std",
"parachain-info/std",
"cumulus-pallet-aura-ext/std",
"pallet-asset-tx-payment/std",
"pallet-collator-selection/std",
"cumulus-pallet-dmp-queue/std",
"cumulus-pallet-parachain-system/std",
+18 -18
View File
@@ -29,9 +29,9 @@ use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT},
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, Perbill,
ApplyExtrinsicResult,
};
use sp_std::prelude::*;
@@ -56,7 +56,7 @@ use frame_system::{
};
pub use parachains_common as common;
use parachains_common::{
impls::{DealWithFees, NonZeroIssuance},
impls::{AssetsToBlockAuthor, DealWithFees, NonZeroIssuance},
opaque, AccountId, AssetId, AuraId, Balance, BlockNumber, Hash, Header, Index, Signature,
AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION,
};
@@ -90,10 +90,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("westmint"),
impl_name: create_runtime_str!("westmint"),
authoring_version: 1,
spec_version: 3,
spec_version: 5,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
transaction_version: 3,
};
/// The version information used to identify this runtime when compiled natively.
@@ -599,7 +599,6 @@ impl cumulus_pallet_dmp_queue::Config for Runtime {
}
parameter_types! {
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33);
pub const Period: u32 = 6 * HOURS;
pub const Offset: u32 = 0;
pub const MaxAuthorities: u32 = 100_000;
@@ -616,7 +615,6 @@ impl pallet_session::Config for Runtime {
// Essentially just Aura, but lets be pedantic.
type SessionHandler = <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = weights::pallet_session::WeightInfo<Runtime>;
}
@@ -650,6 +648,14 @@ impl pallet_collator_selection::Config for Runtime {
type WeightInfo = weights::pallet_collator_selection::WeightInfo<Runtime>;
}
impl pallet_asset_tx_payment::Config for Runtime {
type Fungibles = Assets;
type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter<
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
AssetsToBlockAuthor<Runtime>,
>;
}
parameter_types! {
pub const ClassDeposit: Balance = UNITS; // 1 UNIT deposit to create asset class
pub const InstanceDeposit: Balance = UNITS / 100; // 1/100 UNIT deposit to create asset instance
@@ -720,6 +726,9 @@ construct_runtime!(
// More things for the main stage
Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>},
// More Monetary stuff
AssetTxPayment: pallet_asset_tx_payment::{Pallet},
}
);
@@ -739,7 +748,7 @@ pub type SignedExtra = (
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
pallet_asset_tx_payment::ChargeAssetTxPayment<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
@@ -752,18 +761,9 @@ pub type Executive = frame_executive::Executive<
frame_system::ChainContext<Runtime>,
Runtime,
AllPallets,
OnRuntimeUpgrade,
(),
>;
pub struct OnRuntimeUpgrade;
impl frame_support::traits::OnRuntimeUpgrade for OnRuntimeUpgrade {
fn on_runtime_upgrade() -> u64 {
frame_support::migrations::migrate_from_pallet_version_to_storage_version::<
AllPalletsWithSystem,
>(&RocksDbWeight::get())
}
}
impl_runtime_apis! {
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> sp_consensus_aura::SlotDuration {
+21 -2
View File
@@ -2,10 +2,15 @@
steps=50
repeat=20
statemineOutput=./polkadot-parachains/statemine-runtime/src/weights
statemintOutput=./polkadot-parachains/statemint-runtime/src/weights
statemineOutput=./polkadot-parachains/statemine/src/weights
statemintOutput=./polkadot-parachains/statemint/src/weights
westmintOutput=./polkadot-parachains/westmint/src/weights
statemineChain=statemine-dev
statemintChain=statemint-dev
westmintChain=westmint-dev
pallets=(
pallet_assets
pallet_balances
@@ -15,6 +20,7 @@ pallets=(
pallet_session
pallet_timestamp
pallet_utility
pallet_uniques
)
for p in ${pallets[@]}
@@ -28,6 +34,7 @@ do
--steps=$steps \
--repeat=$repeat \
--raw \
--header=./file_header.txt \
--output=$statemineOutput
./target/release/polkadot-collator benchmark \
@@ -39,6 +46,18 @@ do
--steps=$steps \
--repeat=$repeat \
--raw \
--header=./file_header.txt \
--output=$statemintOutput
./target/release/polkadot-collator benchmark \
--chain=$westmintChain \
--execution=wasm \
--wasm-execution=compiled \
--pallet=$p \
--extrinsic='*' \
--steps=$steps \
--repeat=$repeat \
--raw \
--header=./file_header.txt \
--output=$westmintOutput
done