git.delta.rocks / unique-network / refs/commits / ea3a682dbe54

difftreelog

fix only enable sponsoring if rate limit is on

Yaroslav Bolyukin2021-07-28parent: #8a7066a.patch.diff
in: master

1 file changed

modifiedpallets/contract-helpers/src/lib.rsdiffbeforeafterboth
before · pallets/contract-helpers/src/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]23pub use pallet::*;45#[frame_support::pallet]6pub mod pallet {7	use frame_support::sp_runtime::traits::StaticLookup;8	use frame_support::{pallet_prelude::*, traits::IsSubType};9	use frame_system::pallet_prelude::*;10	use pallet_contracts::chain_extension::UncheckedFrom;11	use sp_runtime::{12		traits::{DispatchInfoOf, Hash, PostDispatchInfoOf, SignedExtension},13		transaction_validity,14	};15	use sp_std::vec::Vec;16	use up_sponsorship::SponsorshipHandler;1718	#[pallet::error]19	pub enum Error<T> {20		/// Should be contract owner21		NoPermission,22	}2324	#[pallet::config]25	pub trait Config: frame_system::Config + pallet_contracts::Config {26		type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;27	}2829	#[pallet::pallet]30	#[pallet::generate_store(pub(super) trait Store)]31	pub struct Pallet<T>(_);3233	#[pallet::storage]34	pub(super) type Owner<T: Config> = StorageMap<35		Hasher = Twox128,36		Key = T::AccountId,37		Value = T::AccountId,38		QueryKind = ValueQuery,39	>;4041	#[pallet::storage]42	pub(super) type AllowlistEnabled<T: Config> =43		StorageMap<Hasher = Twox128, Key = T::AccountId, Value = bool, QueryKind = ValueQuery>;4445	#[pallet::storage]46	pub(super) type Allowlist<T: Config> = StorageDoubleMap<47		Hasher1 = Twox128,48		Key1 = T::AccountId,49		Hasher2 = Twox64Concat,50		Key2 = T::AccountId,51		Value = bool,52		QueryKind = ValueQuery,53	>;5455	#[pallet::storage]56	pub(super) type SelfSponsoring<T: Config> =57		StorageMap<Hasher = Twox128, Key = T::AccountId, Value = bool, QueryKind = ValueQuery>;5859	#[pallet::storage]60	pub(super) type SponsoringRateLimit<T: Config> = StorageMap<61		Hasher = Twox128,62		Key = T::AccountId,63		Value = T::BlockNumber,64		QueryKind = ValueQuery,65		OnEmpty = T::DefaultSponsoringRateLimit,66	>;6768	#[pallet::storage]69	pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<70		Hasher1 = Twox128,71		Key1 = T::AccountId,72		Hasher2 = Twox128,73		Key2 = T::AccountId,74		Value = T::BlockNumber,75		QueryKind = OptionQuery,76	>;7778	#[pallet::call]79	impl<T: Config> Pallet<T> {80		#[pallet::weight(0)]81		pub fn toggle_sponsoring(82			origin: OriginFor<T>,83			contract: T::AccountId,84			sponsoring: bool,85		) -> DispatchResult {86			let sender = ensure_signed(origin)?;87			ensure!(88				<Owner<T>>::get(&contract) == sender,89				<Error<T>>::NoPermission90			);9192			if sponsoring {93				<SelfSponsoring<T>>::insert(contract, true);94			} else {95				<SelfSponsoring<T>>::remove(contract);96			}97			Ok(())98		}99100		#[pallet::weight(0)]101		pub fn toggle_allowlist(102			origin: OriginFor<T>,103			contract: T::AccountId,104			enabled: bool,105		) -> DispatchResult {106			let sender = ensure_signed(origin)?;107			ensure!(108				<Owner<T>>::get(&contract) == sender,109				<Error<T>>::NoPermission110			);111112			if enabled {113				<AllowlistEnabled<T>>::insert(contract, true);114			} else {115				<AllowlistEnabled<T>>::remove(contract);116			}117			Ok(())118		}119120		#[pallet::weight(0)]121		pub fn toggle_allowed(122			origin: OriginFor<T>,123			contract: T::AccountId,124			user: T::AccountId,125			allowed: bool,126		) -> DispatchResult {127			let sender = ensure_signed(origin)?;128			ensure!(129				<Owner<T>>::get(&contract) == sender,130				<Error<T>>::NoPermission131			);132133			if allowed {134				<Allowlist<T>>::insert(contract, user, true);135			} else {136				<Allowlist<T>>::remove(contract, user);137			}138			Ok(())139		}140141		#[pallet::weight(0)]142		pub fn set_sponsoring_rate_limit(143			origin: OriginFor<T>,144			contract: T::AccountId,145			rate_limit: T::BlockNumber,146		) -> DispatchResult {147			let sender = ensure_signed(origin)?;148			ensure!(149				<Owner<T>>::get(&contract) == sender,150				<Error<T>>::NoPermission151			);152153			<SponsoringRateLimit<T>>::insert(contract, rate_limit);154			Ok(())155		}156	}157158	#[derive(Encode, Decode, Clone, PartialEq, Eq)]159	pub struct ContractHelpersExtension<T>(PhantomData<T>);160	impl<T> core::fmt::Debug for ContractHelpersExtension<T> {161		fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {162			fmt.debug_struct("ContractHelpersExtension").finish()163		}164	}165166	type CodeHash<T> = <T as frame_system::Config>::Hash;167	impl<T> SignedExtension for ContractHelpersExtension<T>168	where169		T: Config + Send + Sync,170		T::Call: sp_runtime::traits::Dispatchable,171		T::Call: IsSubType<pallet_contracts::Call<T>>,172		T::AccountId: UncheckedFrom<T::Hash>,173		T::AccountId: AsRef<[u8]>,174	{175		const IDENTIFIER: &'static str = "ContractHelpers";176		type AccountId = T::AccountId;177		type Call = T::Call;178		type AdditionalSigned = ();179		type Pre = Option<(Self::AccountId, CodeHash<T>, Vec<u8>)>;180181		fn additional_signed(&self) -> Result<(), transaction_validity::TransactionValidityError> {182			Ok(())183		}184185		fn validate(186			&self,187			who: &T::AccountId,188			call: &Self::Call,189			_info: &DispatchInfoOf<Self::Call>,190			_len: usize,191		) -> transaction_validity::TransactionValidity {192			if let Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) =193				IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call)194			{195				let called_contract: T::AccountId =196					T::Lookup::lookup((*dest).clone()).unwrap_or_default();197				if <AllowlistEnabled<T>>::get(&called_contract)198					&& !<Allowlist<T>>::get(&called_contract, who)199					&& &<Owner<T>>::get(&called_contract) != who200				{201					return Err(transaction_validity::InvalidTransaction::Call.into());202				}203			}204			Ok(transaction_validity::ValidTransaction::default())205		}206207		fn pre_dispatch(208			self,209			who: &Self::AccountId,210			call: &Self::Call,211			_info: &DispatchInfoOf<Self::Call>,212			_len: usize,213		) -> Result<Self::Pre, TransactionValidityError> {214			match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {215				Some(pallet_contracts::Call::instantiate(_, _, code_hash, _, salt)) => {216					Ok(Some((who.clone(), *code_hash, salt.clone())))217				}218				Some(pallet_contracts::Call::instantiate_with_code(_, _, code, _, salt)) => {219					let code_hash = &T::Hashing::hash(code);220					Ok(Some((who.clone(), *code_hash, salt.clone())))221				}222				_ => Ok(None),223			}224		}225226		fn post_dispatch(227			pre: Self::Pre,228			_info: &DispatchInfoOf<Self::Call>,229			_post_info: &PostDispatchInfoOf<Self::Call>,230			_len: usize,231			_result: &DispatchResult,232		) -> Result<(), TransactionValidityError> {233			if let Some((who, code_hash, salt)) = pre {234				let new_contract_address =235					<pallet_contracts::Pallet<T>>::contract_address(&who, &code_hash, &salt);236				<Owner<T>>::insert(&new_contract_address, &who);237			}238239			Ok(())240		}241	}242243	pub struct ContractSponsorshipHandler<T>(PhantomData<T>);244	impl<T, C> SponsorshipHandler<T::AccountId, C> for ContractSponsorshipHandler<T>245	where246		T: Config,247		C: IsSubType<pallet_contracts::Call<T>>,248		T::AccountId: UncheckedFrom<T::Hash>,249		T::AccountId: AsRef<[u8]>,250	{251		fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {252			if let Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) =253				IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call)254			{255				let called_contract: T::AccountId =256					T::Lookup::lookup((*dest).clone()).unwrap_or_default();257				if <SelfSponsoring<T>>::get(&called_contract) {258					let last_tx_block = SponsorBasket::<T>::get(&called_contract, &who);259					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;260					let rate_limit = SponsoringRateLimit::<T>::get(&called_contract);261					let limit_time = last_tx_block + rate_limit;262263					if block_number >= limit_time {264						SponsorBasket::<T>::insert(&called_contract, who, block_number);265						return Some(called_contract);266					}267				}268			}269			None270		}271	}272}