git.delta.rocks / unique-network / refs/commits / 82ca9c1be6da

difftreelog

Merge pull request #25 from usetech-llc/feature/NFTPAR-110_contract_spam

str-mv2020-12-02parents: #61a5f4d #33c31e8.patch.diff
in: master
Feature/nftpar 110 contract spam protection

4 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3737,7 +3737,10 @@
  "frame-support",
  "frame-system",
  "log",
+ "pallet-balances",
  "pallet-contracts",
+ "pallet-randomness-collective-flip",
+ "pallet-timestamp",
  "pallet-transaction-payment",
  "parity-scale-codec",
  "serde",
modifiedpallets/nft/src/default_weights.rsdiffbeforeafterboth
--- a/pallets/nft/src/default_weights.rs
+++ b/pallets/nft/src/default_weights.rs
@@ -107,9 +107,19 @@
             .saturating_add(DbWeight::get().reads(2 as Weight))
             .saturating_add(DbWeight::get().writes(1 as Weight))
     }
+    // fn set_chain_limits() -> Weight {
+    //     (0 as Weight)
+    //         .saturating_add(DbWeight::get().reads(1 as Weight))
+    //         .saturating_add(DbWeight::get().writes(1 as Weight))
+    // }
     // fn enable_contract_sponsoring() -> Weight {
     //     (0 as Weight)
     //         .saturating_add(DbWeight::get().reads(1 as Weight))
     //         .saturating_add(DbWeight::get().writes(1 as Weight))
     // }
+    // fn set_contract_sponsoring_rate_limit() -> Weight {
+    //     (0 as Weight)
+    //         .saturating_add(DbWeight::get().reads(1 as Weight))
+    //         .saturating_add(DbWeight::get().writes(1 as Weight))
+    // }
 }
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -366,8 +366,10 @@
         pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;
 
         // Contract Sponsorship and Ownership
-        pub ContractOwner get(fn contract_owner): map hasher(identity) T::AccountId => T::AccountId;
-        pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(identity) T::AccountId => bool;
+        pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;
+        pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;
+        pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;
+        pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;
     }
     add_extra_genesis {
         build(|config: &GenesisConfig<T>| {
@@ -1323,6 +1325,41 @@
             Ok(())
         }
 
+        /// Set the rate limit for contract sponsoring to specified number of blocks.
+        /// 
+        /// If not set (has the default value of 0 blocks), the sponsoring will be disabled. 
+        /// If set to the number B (for blocks), the transactions will be sponsored with a rate 
+        /// limit of B, i.e. fees for every transaction sent to this smart contract will be paid 
+        /// from contract endowment if there are at least B blocks between such transactions. 
+        /// Nonetheless, if transactions are sent more frequently, the fees are paid by the sender.
+        /// 
+        /// # Permissions
+        /// 
+        /// * Contract Owner
+        /// 
+        /// # Arguments
+        /// 
+        /// -`contract_address`: Address of the contract to sponsor
+        /// -`rate_limit`: Number of blocks to wait until the next sponsored transaction is allowed
+        /// 
+        #[weight = 0]
+        pub fn set_contract_sponsoring_rate_limit(
+            origin,
+            contract_address: T::AccountId,
+            rate_limit: T::BlockNumber
+        ) -> DispatchResult {
+            let sender = ensure_signed(origin)?;
+            let mut is_owner = false;
+            if <ContractOwner<T>>::contains_key(contract_address.clone()) {
+                let owner = <ContractOwner<T>>::get(&contract_address);
+                is_owner = sender == owner;
+            }
+            ensure!(is_owner, Error::<T>::NoPermission);
+
+            <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);
+            Ok(())
+        }
+
     }
 }
 
@@ -2230,11 +2267,30 @@
             // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is
             Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {
 
+                let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());
+
+                let mut sponsor_transfer = false;
+                if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {
+                    let last_tx_block = <ContractSponsorBasket<T>>::get(&called_contract);
+                    let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
+                    let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);
+                    let limit_time = last_tx_block + rate_limit;
+
+                    if block_number >= limit_time {
+                        <ContractSponsorBasket<T>>::insert(called_contract.clone(), block_number);
+                        sponsor_transfer = true;
+                    }
+                } else {
+                    sponsor_transfer = false;
+                }
+               
+                
                 let mut sp = T::AccountId::default();
-                let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());
-                if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {
-                    if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {
-                        sp = called_contract;
+                if sponsor_transfer {
+                    if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {
+                        if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {
+                            sp = called_contract;
+                        }
                     }
                 }
 
modifiedruntime/src/nft_weights.rsdiffbeforeafterboth
before · runtime/src/nft_weights.rs
1use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};23pub struct WeightInfo;4impl pallet_nft::WeightInfo for WeightInfo {5	fn create_collection() -> Weight {6		(70_000_000 as Weight)7			.saturating_add(DbWeight::get().reads(7 as Weight))8			.saturating_add(DbWeight::get().writes(5 as Weight))9	}10	fn destroy_collection() -> Weight {11		(90_000_000 as Weight)12			.saturating_add(DbWeight::get().reads(2 as Weight))13			.saturating_add(DbWeight::get().writes(5 as Weight))14	}15	fn add_to_white_list() -> Weight {16		(30_000_000 as Weight)17			.saturating_add(DbWeight::get().reads(3 as Weight))18			.saturating_add(DbWeight::get().writes(1 as Weight))19    }20    fn remove_from_white_list() -> Weight {21		(35_000_000 as Weight)22			.saturating_add(DbWeight::get().reads(3 as Weight))23			.saturating_add(DbWeight::get().writes(1 as Weight))24	}25	fn set_public_access_mode() -> Weight {26		(27_000_000 as Weight)27			.saturating_add(DbWeight::get().reads(1 as Weight))28			.saturating_add(DbWeight::get().writes(1 as Weight))29	}30	fn set_mint_permission() -> Weight {31		(27_000_000 as Weight)32			.saturating_add(DbWeight::get().reads(1 as Weight))33			.saturating_add(DbWeight::get().writes(1 as Weight))34	}35	fn change_collection_owner() -> Weight {36		(27_000_000 as Weight)37			.saturating_add(DbWeight::get().reads(1 as Weight))38			.saturating_add(DbWeight::get().writes(1 as Weight))39	}40	fn add_collection_admin() -> Weight {41        (32_000_000 as Weight)42            .saturating_add(DbWeight::get().reads(3 as Weight))43            .saturating_add(DbWeight::get().writes(1 as Weight))44	}45	fn remove_collection_admin() -> Weight {46		(50_000_000 as Weight)47            .saturating_add(DbWeight::get().reads(2 as Weight))48            .saturating_add(DbWeight::get().writes(1 as Weight))49    }50    fn set_collection_sponsor() -> Weight {51		(32_000_000 as Weight)52            .saturating_add(DbWeight::get().reads(2 as Weight))53            .saturating_add(DbWeight::get().writes(1 as Weight))54    }  55    fn confirm_sponsorship() -> Weight {56		(22_000_000 as Weight)57            .saturating_add(DbWeight::get().reads(1 as Weight))58            .saturating_add(DbWeight::get().writes(1 as Weight))59    }  60    fn remove_collection_sponsor() -> Weight {61		(24_000_000 as Weight)62            .saturating_add(DbWeight::get().reads(1 as Weight))63            .saturating_add(DbWeight::get().writes(1 as Weight))64    }  65    fn create_item(s: usize, ) -> Weight {66        (130_000_000 as Weight)67            .saturating_add((2135 as Weight).saturating_mul(s as Weight).saturating_mul(500 as Weight)) // 500 is temparary multiplier, fee for storage68            .saturating_add(DbWeight::get().reads(10 as Weight))69            .saturating_add(DbWeight::get().writes(8 as Weight))70    }  71    fn burn_item() -> Weight {72		(170_000_000 as Weight)73            .saturating_add(DbWeight::get().reads(9 as Weight))74            .saturating_add(DbWeight::get().writes(7 as Weight))75    }  76    fn transfer() -> Weight {77        (125_000_000 as Weight)78            .saturating_add(DbWeight::get().reads(7 as Weight))79            .saturating_add(DbWeight::get().writes(7 as Weight))80    }  81    fn approve() -> Weight {82        (45_000_000 as Weight)83            .saturating_add(DbWeight::get().reads(3 as Weight))84            .saturating_add(DbWeight::get().writes(1 as Weight))85    }86    fn transfer_from() -> Weight {87        (150_000_000 as Weight)88            .saturating_add(DbWeight::get().reads(9 as Weight))89            .saturating_add(DbWeight::get().writes(8 as Weight))90    }91    fn set_offchain_schema() -> Weight {92        (33_000_000 as Weight)93            .saturating_add(DbWeight::get().reads(2 as Weight))94            .saturating_add(DbWeight::get().writes(1 as Weight))95    }96    fn set_const_on_chain_schema() -> Weight {97        (11_100_000 as Weight)98            .saturating_add(DbWeight::get().reads(2 as Weight))99            .saturating_add(DbWeight::get().writes(1 as Weight))100    }101    fn set_variable_on_chain_schema() -> Weight {102        (11_100_000 as Weight)103            .saturating_add(DbWeight::get().reads(2 as Weight))104            .saturating_add(DbWeight::get().writes(1 as Weight))105    }106    fn set_variable_meta_data() -> Weight {107        (17_500_000 as Weight)108            .saturating_add(DbWeight::get().reads(2 as Weight))109            .saturating_add(DbWeight::get().writes(1 as Weight))110    }111}
after · runtime/src/nft_weights.rs
1use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};23pub struct WeightInfo;4impl pallet_nft::WeightInfo for WeightInfo {5	fn create_collection() -> Weight {6		(70_000_000 as Weight)7			.saturating_add(DbWeight::get().reads(7 as Weight))8			.saturating_add(DbWeight::get().writes(5 as Weight))9	}10	fn destroy_collection() -> Weight {11		(90_000_000 as Weight)12			.saturating_add(DbWeight::get().reads(2 as Weight))13			.saturating_add(DbWeight::get().writes(5 as Weight))14	}15	fn add_to_white_list() -> Weight {16		(30_000_000 as Weight)17			.saturating_add(DbWeight::get().reads(3 as Weight))18			.saturating_add(DbWeight::get().writes(1 as Weight))19    }20    fn remove_from_white_list() -> Weight {21		(35_000_000 as Weight)22			.saturating_add(DbWeight::get().reads(3 as Weight))23			.saturating_add(DbWeight::get().writes(1 as Weight))24	}25	fn set_public_access_mode() -> Weight {26		(27_000_000 as Weight)27			.saturating_add(DbWeight::get().reads(1 as Weight))28			.saturating_add(DbWeight::get().writes(1 as Weight))29	}30	fn set_mint_permission() -> Weight {31		(27_000_000 as Weight)32			.saturating_add(DbWeight::get().reads(1 as Weight))33			.saturating_add(DbWeight::get().writes(1 as Weight))34	}35	fn change_collection_owner() -> Weight {36		(27_000_000 as Weight)37			.saturating_add(DbWeight::get().reads(1 as Weight))38			.saturating_add(DbWeight::get().writes(1 as Weight))39	}40	fn add_collection_admin() -> Weight {41        (32_000_000 as Weight)42            .saturating_add(DbWeight::get().reads(3 as Weight))43            .saturating_add(DbWeight::get().writes(1 as Weight))44	}45	fn remove_collection_admin() -> Weight {46		(50_000_000 as Weight)47            .saturating_add(DbWeight::get().reads(2 as Weight))48            .saturating_add(DbWeight::get().writes(1 as Weight))49    }50    fn set_collection_sponsor() -> Weight {51		(32_000_000 as Weight)52            .saturating_add(DbWeight::get().reads(2 as Weight))53            .saturating_add(DbWeight::get().writes(1 as Weight))54    }  55    fn confirm_sponsorship() -> Weight {56		(22_000_000 as Weight)57            .saturating_add(DbWeight::get().reads(1 as Weight))58            .saturating_add(DbWeight::get().writes(1 as Weight))59    }  60    fn remove_collection_sponsor() -> Weight {61		(24_000_000 as Weight)62            .saturating_add(DbWeight::get().reads(1 as Weight))63            .saturating_add(DbWeight::get().writes(1 as Weight))64    }  65    fn create_item(s: usize, ) -> Weight {66        (130_000_000 as Weight)67            .saturating_add((2135 as Weight).saturating_mul(s as Weight).saturating_mul(500 as Weight)) // 500 is temparary multiplier, fee for storage68            .saturating_add(DbWeight::get().reads(10 as Weight))69            .saturating_add(DbWeight::get().writes(8 as Weight))70    }  71    fn burn_item() -> Weight {72		(170_000_000 as Weight)73            .saturating_add(DbWeight::get().reads(9 as Weight))74            .saturating_add(DbWeight::get().writes(7 as Weight))75    }  76    fn transfer() -> Weight {77        (125_000_000 as Weight)78            .saturating_add(DbWeight::get().reads(7 as Weight))79            .saturating_add(DbWeight::get().writes(7 as Weight))80    }  81    fn approve() -> Weight {82        (45_000_000 as Weight)83            .saturating_add(DbWeight::get().reads(3 as Weight))84            .saturating_add(DbWeight::get().writes(1 as Weight))85    }86    fn transfer_from() -> Weight {87        (150_000_000 as Weight)88            .saturating_add(DbWeight::get().reads(9 as Weight))89            .saturating_add(DbWeight::get().writes(8 as Weight))90    }91    fn set_offchain_schema() -> Weight {92        (33_000_000 as Weight)93            .saturating_add(DbWeight::get().reads(2 as Weight))94            .saturating_add(DbWeight::get().writes(1 as Weight))95    }96    fn set_const_on_chain_schema() -> Weight {97        (11_100_000 as Weight)98            .saturating_add(DbWeight::get().reads(2 as Weight))99            .saturating_add(DbWeight::get().writes(1 as Weight))100    }101    fn set_variable_on_chain_schema() -> Weight {102        (11_100_000 as Weight)103            .saturating_add(DbWeight::get().reads(2 as Weight))104            .saturating_add(DbWeight::get().writes(1 as Weight))105    }106    fn set_variable_meta_data() -> Weight {107        (17_500_000 as Weight)108            .saturating_add(DbWeight::get().reads(2 as Weight))109            .saturating_add(DbWeight::get().writes(1 as Weight))110    }111    // fn set_chain_limits() -> Weight {112    //     (0 as Weight)113    //         .saturating_add(DbWeight::get().reads(1 as Weight))114    //         .saturating_add(DbWeight::get().writes(1 as Weight))115    // }116    // fn enable_contract_sponsoring() -> Weight {117    //     (0 as Weight)118    //         .saturating_add(DbWeight::get().reads(1 as Weight))119    //         .saturating_add(DbWeight::get().writes(1 as Weight))120    // }121    // fn set_contract_sponsoring_rate_limit() -> Weight {122    //     (0 as Weight)123    //         .saturating_add(DbWeight::get().reads(1 as Weight))124    //         .saturating_add(DbWeight::get().writes(1 as Weight))125    // }126}