difftreelog
Scheduler refactored and fixed
in: master
8 files changed
pallets/nft-charge-transaction/src/lib.rsdiffbeforeafterboth135 .map(|i| (fee, i));135 .map(|i| (fee, i));136 }136 }137138 // check errors139 let error = <pallet_nft_transaction_payment::Module<T>>::check_error(who, call);140 match error {141 Err(error) => return Err(error),142 Ok(error) => {}143 };137144138 // Determine who is paying transaction fee based on ecnomic model145 // Determine who is paying transaction fee based on ecnomic model139 // Parse call to extract collection ID and access collection sponsor 146 // Parse call to extract collection ID and access collection sponsor pallets/nft-transaction-payment/README.mddiffbeforeafterbothno changes
pallets/nft-transaction-payment/src/lib.rsdiffbeforeafterboth31 traits::{ 31 traits::{ 32 Hash, Dispatchable,32 Hash, Dispatchable,33 },33 },34 transaction_validity::{35 InvalidTransaction, TransactionValidityError,36 },34};37};35use pallet_contracts::chain_extension::UncheckedFrom;38use pallet_contracts::chain_extension::UncheckedFrom;36use sp_std::prelude::*;39use sp_std::prelude::*;85impl<T: Config> Module<T> 88impl<T: Config> Module<T> 86{89{9091 pub fn check_error(92 who: &T::AccountId,93 call: &T::Call94 ) -> Result<bool, TransactionValidityError> where 95 T::Call: Dispatchable<Info=DispatchInfo>,96 T::Call: IsSubType<pallet_nft::Call<T>>, 97 T::Call: IsSubType<pallet_contracts::Call<T>>,98 T::AccountId: AsRef<[u8]>,99 T::AccountId: UncheckedFrom<T::Hash>100 {101102 match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {103 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {104 105 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());106 107 let owned_contract = pallet_nft::ContractOwner::<T>::get(called_contract.clone()).as_ref() == Some(who);108 let white_list_enabled = pallet_nft::ContractWhiteListEnabled::<T>::contains_key(called_contract.clone());109 110 if !owned_contract && white_list_enabled {111 if !pallet_nft::ContractWhiteList::<T>::contains_key(called_contract.clone(), who) {112 return Err(InvalidTransaction::Call.into());113 }114 }115 Ok(true)116 },117 _ => { Ok(true) },118 }119 }8712088 pub fn withdraw_type(121 pub fn withdraw_type(89 who: &T::AccountId,122 who: &T::AccountId,368 }401 }369}402}370371// type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;372373// /// Require the transactor pay for themselves and maybe include a tip to gain additional priority374// /// in the queue.375// #[derive(Encode, Decode, Clone, Eq, PartialEq)]376// pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);377378// impl<T: Config + Send + Sync> sp_std::fmt::Debug 379// for ChargeTransactionPayment<T>380// {381// #[cfg(feature = "std")]382// fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {383// write!(f, "ChargeTransactionPayment<{:?}>", self.0)384// }385// #[cfg(not(feature = "std"))]386// fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {387// Ok(())388// }389// }390391// impl<T: Config> ChargeTransactionPayment<T>392// where393// T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<pallet_nft::Call<T>> + IsSubType<pallet_contracts::Call<T>>,394// BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,395// T::AccountId: AsRef<[u8]>,396// T::AccountId: UncheckedFrom<T::Hash>,397// {398// fn traditional_fee(399// len: usize,400// info: &DispatchInfoOf<T::Call>,401// tip: BalanceOf<T>,402// ) -> BalanceOf<T>403// where404// T::Call: Dispatchable<Info = DispatchInfo>,405// {406// <pallet_transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)407// }408409// fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {410// let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);411// let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);412// let len_saturation = max_block_length as u64 / (len as u64).max(1);413// let coefficient: BalanceOf<T> = weight_saturation414// .min(len_saturation)415// .saturated_into::<BalanceOf<T>>();416// final_fee417// .saturating_mul(coefficient)418// .saturated_into::<TransactionPriority>()419// }420421// fn withdraw_fee(422// &self,423// who: &T::AccountId,424// call: &T::Call,425// info: &DispatchInfoOf<T::Call>,426// len: usize,427// ) -> Result<428// (429// BalanceOf<T>,430// <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,431// ),432// TransactionValidityError,433// > {434// let tip = self.0;435436// let fee = Self::traditional_fee(len, info, tip);437438// // Only mess with balances if fee is not zero.439// if fee.is_zero() {440// return <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)441// .map(|i| (fee, i));442// }443444// // Determine who is paying transaction fee based on ecnomic model445// // Parse call to extract collection ID and access collection sponsor446 447// let sponsor = pallet_nft_transaction_payment::<T>::withdraw_type(who, call);448// //let sponsor = Self::Module::<T>::withdraw_type(who, call);;449// // <pallet_nft_transaction_payment::Module<T>>::withdraw_type(who, call);450451// let who_pays_fee = sponsor.unwrap_or_else(|| who.clone());452453// <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)454// .map(|i| (fee, i))455// }456// }457458459// impl<T: Config + Send + Sync> SignedExtension460// for ChargeTransactionPayment<T>461// where462// BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,463// T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<pallet_nft::Call<T>> + IsSubType<pallet_contracts::Call<T>>,464// T::AccountId: AsRef<[u8]>,465// T::AccountId: UncheckedFrom<T::Hash>,466// {467// const IDENTIFIER: &'static str = "ChargeTransactionPayment";468// type AccountId = T::AccountId;469// type Call = T::Call;470// type AdditionalSigned = ();471// type Pre = (472// // tip473// BalanceOf<T>,474// // who pays fee475// Self::AccountId,476// // imbalance resulting from withdrawing the fee477// <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,478// );479// fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {480// Ok(())481// }482483// fn validate(484// &self,485// who: &Self::AccountId,486// call: &Self::Call,487// info: &DispatchInfoOf<Self::Call>,488// len: usize,489// ) -> TransactionValidity {490// let (fee, _) = self.withdraw_fee(who, call, info, len)?;491// Ok(ValidTransaction {492// priority: Self::get_priority(len, info, fee),493// ..Default::default()494// })495// }496497// fn pre_dispatch(498// self,499// who: &Self::AccountId,500// call: &Self::Call,501// info: &DispatchInfoOf<Self::Call>,502// len: usize,503// ) -> Result<Self::Pre, TransactionValidityError> {504// let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;505// Ok((self.0, who.clone(), imbalance))506// }507508// fn post_dispatch(509// pre: Self::Pre,510// info: &DispatchInfoOf<Self::Call>,511// post_info: &PostDispatchInfoOf<Self::Call>,512// len: usize,513// _result: &DispatchResult,514// ) -> Result<(), TransactionValidityError> {515// let (tip, who, imbalance) = pre;516// let actual_fee = pallet_transaction_payment::Module::<T>::compute_actual_fee(517// len as u32,518// info,519// post_info,520// tip,521// );522// <T as pallet_transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;523// Ok(())524// }525// }pallets/nft/src/lib.rsdiffbeforeafterboth323233use frame_system::{self as system, ensure_signed, ensure_root};33use frame_system::{self as system, ensure_signed, ensure_root};34use sp_runtime::sp_std::prelude::Vec;34use sp_runtime::sp_std::prelude::Vec;35use core::ops::{Deref, DerefMut};35use nft_data_structs::{36use nft_data_structs::{36 MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, MAX_REFUNGIBLE_PIECES,37 MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, MAX_REFUNGIBLE_PIECES,37 AccessMode, ChainLimits, Collection, CreateItemData, CollectionLimits,38 AccessMode, ChainLimits, Collection, CreateItemData, CollectionLimits,38 CollectionId, CollectionMode, CollectionHandle, TokenId, 39 CollectionId, CollectionMode, TokenId, 39 SchemaVersion, SponsorshipState, Ownership,40 SchemaVersion, SponsorshipState, Ownership,40 NftItemType, FungibleItemType, ReFungibleItemType41 NftItemType, FungibleItemType, ReFungibleItemType41};42};164 }165 }165}166}166167167// + pallet_transaction_payment::Config + pallet_nft_transaction_payment::Config + pallet_contracts::Config168pub struct CollectionHandle<T: frame_system::Config> {169 pub id: CollectionId,170 pub collection: Collection<T>,171}172173impl<T: frame_system::Config> Deref for CollectionHandle<T> {174 type Target = Collection<T>;175176 fn deref(&self) -> &Self::Target {177 &self.collection178 }179}180181impl<T: frame_system::Config> DerefMut for CollectionHandle<T> {182 fn deref_mut(&mut self) -> &mut Self::Target {183 &mut self.collection184 }185}186168187169188pallets/scheduler/src/lib.rsdiffbeforeafterboth102 /// Not strictly enforced, but used for weight estimation.102 /// Not strictly enforced, but used for weight estimation.103 type MaxScheduledPerBlock: Get<u32>;103 type MaxScheduledPerBlock: Get<u32>;104104105 /// TODO105 /// Sponsoring function106 type Sponsoring: SponsoringResolve<Self::AccountId, <Self as Config>::Call>;106 type Sponsoring: SponsoringResolve<Self::AccountId, <Self as Config>::Call>;107107108 /// Weight information for extrinsics in this pallet.108 /// Weight information for extrinsics in this pallet.230 /// - Write: Agenda230 /// - Write: Agenda231 /// - Will use base weight of 25 which should be good for up to 30 scheduled calls231 /// - Will use base weight of 25 which should be good for up to 30 scheduled calls232 /// # </weight>232 /// # </weight>233 // #[weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get())]234 #[weight = 0]233 #[weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get())]235 fn schedule(origin,234 fn schedule(origin,236 when: T::BlockNumber,235 when: T::BlockNumber,237 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,236 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,367 }366 }368 queued.sort_by_key(|(_, s)| s.priority);367 queued.sort_by_key(|(_, s)| s.priority);369 let base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next)368 let base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next)370 let mut total_weight: Weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get());369 let mut total_weight: Weight = 0;371 queued.into_iter()370 queued.into_iter()372 .enumerate()371 .enumerate()373 .scan(base_weight, |cumulative_weight, (order, (index, s))| {372 .scan(base_weight, |cumulative_weight, (order, (index, s))| {407 ).into();406 ).into();408 let sender = ensure_signed(origin).unwrap_or(T::AccountId::default());407 let sender = ensure_signed(origin).unwrap_or(T::AccountId::default());409 let who_will_pay = T::Sponsoring::resolve(&sender, &s.call.clone()).unwrap_or(408 let who_will_pay = T::Sponsoring::resolve(&sender, &s.call.clone()).unwrap_or(410 T::AccountId::default());409 sender);411 let sponsor = T::PalletsOrigin::from(system::RawOrigin::Signed(who_will_pay));410 let sponsor = T::PalletsOrigin::from(system::RawOrigin::Signed(who_will_pay));412 let r = s.call.clone().dispatch(sponsor.into());411 let r = s.call.clone().dispatch(sponsor.into());413 let maybe_id = s.maybe_id.clone();412 let maybe_id = s.maybe_id.clone();tests/src/pallet-presence.test.tsdiffbeforeafterboth131314// Pallets that must always be present14// Pallets that must always be present15const requiredPallets = [15const requiredPallets = [16 'nft', 'inflation', 'balances', 'contracts', 'randomnesscollectiveflip', 'system', 'timestamp', 'transactionpayment', 'treasury', 'vesting'16 'nft', 'inflation', 'balances', 'contracts', 'randomnesscollectiveflip', 'system', 'timestamp', 'transactionpayment', 'treasury', 'vesting',17 'scheduler', 'nftpayment', 'charging'17];18];181919// Pallets that depend on consensus and governance configuration20// Pallets that depend on consensus and governance configurationtests/src/scheduler.test.tsdiffbeforeafterbothno changes
tests/src/util/helpers.tsdiffbeforeafterboth556import { ApiPromise, Keyring } from '@polkadot/api';6import { ApiPromise, Keyring } from '@polkadot/api';7import { Enum, Struct } from '@polkadot/types/codec';7import { Enum, Struct } from '@polkadot/types/codec';8import type { AccountId, EventRecord } from '@polkadot/types/interfaces';8import type { AccountId, BlockNumber, Call, EventRecord } from '@polkadot/types/interfaces';9import { u128 } from '@polkadot/types/primitive';9import { u128 } from '@polkadot/types/primitive';10import { IKeyringPair } from '@polkadot/types/types';10import { IKeyringPair } from '@polkadot/types/types';11import { BigNumber } from 'bignumber.js';11import { BigNumber } from 'bignumber.js';17import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';17import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';18import { ICollectionInterface } from '../types';18import { ICollectionInterface } from '../types';19import { hexToStr, strToUTF16, utf16ToStr } from './util';19import { hexToStr, strToUTF16, utf16ToStr } from './util';20import { Compact, Option, Raw, Vec } from '@polkadot/types/codec';21// import { AccountId, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, Call, ChangesTrieConfiguration, Consensus, ConsensusEngineId, Digest, DigestItem, DispatchClass, DispatchInfo, DispatchInfoTo190, EcdsaSignature, Ed25519Signature, Extrinsic, ExtrinsicEra, ExtrinsicPayload, ExtrinsicPayloadUnknown, ExtrinsicPayloadV1, ExtrinsicPayloadV2, ExtrinsicPayloadV3, ExtrinsicPayloadV4, ExtrinsicSignatureV1, ExtrinsicSignatureV2, ExtrinsicSignatureV3, ExtrinsicSignatureV4, ExtrinsicUnknown, ExtrinsicV1, ExtrinsicV2, ExtrinsicV3, ExtrinsicV4, Hash, Header, ImmortalEra, Index, Justification, KeyTypeId, KeyValue, LockIdentifier, LookupSource, LookupTarget, Moment, MortalEra, MultiSignature, Origin, Perbill, Percent, Permill, Perquintill, Phantom, PhantomData, PreRuntime, Seal, SealV0, Signature, SignedBlock, SignerPayload, Sr25519Signature, ValidatorId, Weight, WeightMultiplier } from '@polkadot/types/interfaces/runtime';202221chai.use(chaiAsPromised);23chai.use(chaiAsPromised);22const expect = chai.expect;24const expect = chai.expect;702 });704 });703}705}706707async function getBlockNumber(api: ApiPromise): Promise<number> {708 return new Promise<number>(async (resolve, reject) => {709 const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {710 unsubscribe();711 resolve(head.number.toNumber());712 });713 });714}715716export async function717scheduleTransferExpectSuccess(collectionId: number,718 tokenId: number,719 sender: IKeyringPair,720 recipient: IKeyringPair,721 value: number | bigint = 1,722 type: string = 'NFT') {723 await usingApi(async (api: ApiPromise) => {724 let balanceBefore = new BN(0);725726727 let blockNumber: number | undefined = await getBlockNumber(api);728 let expectedBlockNumber = blockNumber + 2;729730 expect(blockNumber).to.be.greaterThan(0);731 const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value); 732 const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);733734 const events = await submitTransactionAsync(sender, scheduleTx);735736 const sponsorBalanceBefore = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());737 const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());738739 const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;740 expect(nftItemDataBefore.Owner.toString()).to.be.equal(sender.address);741742 // sleep for 2 blocks743 await new Promise(resolve => setTimeout(resolve, 6000 * 2));744745 const sponsorBalanceAfter = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());746 const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());747748 const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;749 expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);750 expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());751 });752}753704754705export async function755export async function