// This file is part of Substrate. // Copyright (C) 2018-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. //! # Contract Pallet //! //! The Contract module provides functionality for the runtime to deploy and execute WebAssembly smart-contracts. //! //! - [`Config`] //! - [`Call`] //! //! ## Overview //! //! This module extends accounts based on the `Currency` trait to have smart-contract functionality. It can //! be used with other modules that implement accounts based on `Currency`. These "smart-contract accounts" //! have the ability to instantiate smart-contracts and make calls to other contract and non-contract accounts. //! //! The smart-contract code is stored once in a `code_cache`, and later retrievable via its `code_hash`. //! This means that multiple smart-contracts can be instantiated from the same `code_cache`, without replicating //! the code each time. //! //! When a smart-contract is called, its associated code is retrieved via the code hash and gets executed. //! This call can alter the storage entries of the smart-contract account, instantiate new smart-contracts, //! or call other smart-contracts. //! //! Finally, when an account is reaped, its associated code and storage of the smart-contract account //! will also be deleted. //! //! ### Gas //! //! Senders must specify a gas limit with every call, as all instructions invoked by the smart-contract require gas. //! Unused gas is refunded after the call, regardless of the execution outcome. //! //! If the gas limit is reached, then all calls and state changes (including balance transfers) are only //! reverted at the current call's contract level. For example, if contract A calls B and B runs out of gas mid-call, //! then all of B's calls are reverted. Assuming correct error handling by contract A, A's other calls and state //! changes still persist. //! //! ### Notable Scenarios //! //! Contract call failures are not always cascading. When failures occur in a sub-call, they do not "bubble up", //! and the call will only revert at the specific contract level. For example, if contract A calls contract B, and B //! fails, A can decide how to handle that failure, either proceeding or reverting A's changes. //! //! ## Interface //! //! ### Dispatchable functions //! //! * `instantiate_with_code` - Deploys a new contract from the supplied wasm binary, optionally transferring //! some balance. This instantiates a new smart contract account and calls its contract deploy //! handler to initialize the contract. //! * `instantiate` - The same as `instantiate_with_code` but instead of uploading new code an //! existing `code_hash` is supplied. //! * `call` - Makes a call to an account, optionally transferring some balance. //! //! ## Usage //! //! The Contract module is a work in progress. The following examples show how this Contract module //! can be used to instantiate and call contracts. //! //! * [`ink`](https://github.com/paritytech/ink) is //! an [`eDSL`](https://wiki.haskell.org/Embedded_domain_specific_language) that enables writing //! WebAssembly based smart contracts in the Rust programming language. This is a work in progress. //! //! ## Related Modules //! //! * [Balances](../pallet_balances/index.html) #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "runtime-benchmarks", recursion_limit="512")] #[macro_use] mod gas; mod storage; mod exec; mod wasm; mod rent; mod benchmarking; mod schedule; mod migration; pub mod chain_extension; pub mod weights; #[cfg(test)] mod tests; pub use crate::{ wasm::PrefabWasmModule, schedule::{Schedule, HostFnWeights, InstructionWeights, Limits}, pallet::*, }; use crate::{ gas::GasMeter, exec::{ExecutionContext, Executable}, rent::Rent, storage::{Storage, DeletedContract}, weights::WeightInfo, }; use sp_core::crypto::UncheckedFrom; use sp_std::{prelude::*, marker::PhantomData, fmt::Debug}; use codec::{Codec, Encode, Decode}; use sp_runtime::{ traits::{ Hash, StaticLookup, MaybeSerializeDeserialize, Member, Convert, Saturating, Zero, }, RuntimeDebug, Perbill, }; use frame_support::{ storage::child::ChildInfo, traits::{OnUnbalanced, Currency, Get, Time, Randomness}, weights::{Weight, PostDispatchInfo, WithPostDispatchInfo}, }; use frame_system::Pallet as System; use pallet_contracts_primitives::{ RentProjectionResult, GetStorageResult, ContractAccessError, ContractExecResult, }; pub type CodeHash = ::Hash; pub type TrieId = Vec; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; pub type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; pub type AliveContractInfo = RawAliveContractInfo, BalanceOf, ::BlockNumber>; pub type TombstoneContractInfo = RawTombstoneContractInfo<::Hash, ::Hashing>; #[frame_support::pallet] pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use super::*; #[pallet::config] pub trait Config: frame_system::Config { /// The time implementation used to supply timestamps to conntracts through `seal_now`. type Time: Time; /// The generator used to supply randomness to contracts through `seal_random`. type Randomness: Randomness; /// The currency in which fees are paid and contract balances are held. type Currency: Currency; /// The overarching event type. type Event: From> + IsType<::Event>; /// Handler for rent payments. type RentPayment: OnUnbalanced>; /// Number of block delay an extrinsic claim surcharge has. /// /// When claim surcharge is called by an extrinsic the rent is checked /// for current_block - delay #[pallet::constant] type SignedClaimHandicap: Get; /// The minimum amount required to generate a tombstone. #[pallet::constant] type TombstoneDeposit: Get>; /// The balance every contract needs to deposit to stay alive indefinitely. /// /// This is different from the [`Self::TombstoneDeposit`] because this only needs to be /// deposited while the contract is alive. Costs for additional storage are added to /// this base cost. /// /// This is a simple way to ensure that contracts with empty storage eventually get deleted by /// making them pay rent. This creates an incentive to remove them early in order to save rent. #[pallet::constant] type DepositPerContract: Get>; /// The balance a contract needs to deposit per storage byte to stay alive indefinitely. /// /// Let's suppose the deposit is 1,000 BU (balance units)/byte and the rent is 1 BU/byte/day, /// then a contract with 1,000,000 BU that uses 1,000 bytes of storage would pay no rent. /// But if the balance reduced to 500,000 BU and the storage stayed the same at 1,000, /// then it would pay 500 BU/day. #[pallet::constant] type DepositPerStorageByte: Get>; /// The balance a contract needs to deposit per storage item to stay alive indefinitely. /// /// It works the same as [`Self::DepositPerStorageByte`] but for storage items. #[pallet::constant] type DepositPerStorageItem: Get>; /// The fraction of the deposit that should be used as rent per block. /// /// When a contract hasn't enough balance deposited to stay alive indefinitely it needs /// to pay per block for the storage it consumes that is not covered by the deposit. /// This determines how high this rent payment is per block as a fraction of the deposit. #[pallet::constant] type RentFraction: Get; /// Reward that is received by the party whose touch has led /// to removal of a contract. #[pallet::constant] type SurchargeReward: Get>; /// The maximum nesting level of a call/instantiate stack. #[pallet::constant] type MaxDepth: Get; /// The maximum size of a storage value and event payload in bytes. #[pallet::constant] type MaxValueSize: Get; /// Used to answer contracts' queries regarding the current weight price. This is **not** /// used to calculate the actual fee and is only for informational purposes. type WeightPrice: Convert>; /// Describes the weights of the dispatchables of this module and is also used to /// construct a default cost schedule. type WeightInfo: WeightInfo; /// Type that allows the runtime authors to add new host functions for a contract to call. type ChainExtension: chain_extension::ChainExtension; /// The maximum number of tries that can be queued for deletion. #[pallet::constant] type DeletionQueueDepth: Get; /// The maximum amount of weight that can be consumed per block for lazy trie removal. #[pallet::constant] type DeletionWeightLimit: Get; /// The maximum length of a contract code in bytes. This limit applies to the instrumented /// version of the code. Therefore `instantiate_with_code` can fail even when supplying /// a wasm binary below this maximum size. #[pallet::constant] type MaxCodeSize: Get; } #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData); #[pallet::hooks] impl Hooks> for Pallet where T::AccountId: UncheckedFrom, T::AccountId: AsRef<[u8]>, { fn on_initialize(_block: T::BlockNumber) -> Weight { // We do not want to go above the block limit and rather avoid lazy deletion // in that case. This should only happen on runtime upgrades. let weight_limit = T::BlockWeights::get().max_block .saturating_sub(System::::block_weight().total()) .min(T::DeletionWeightLimit::get()); Storage::::process_deletion_queue_batch(weight_limit) .saturating_add(T::WeightInfo::on_initialize()) } fn on_runtime_upgrade() -> Weight { migration::migrate::() } } #[pallet::call] impl Pallet where T::AccountId: UncheckedFrom, T::AccountId: AsRef<[u8]>, { /// Updates the schedule for metering contracts. /// /// The schedule's version cannot be less than the version of the stored schedule. /// If a schedule does not change the instruction weights the version does not /// need to be increased. Therefore we allow storing a schedule that has the same /// version as the stored one. #[pallet::weight(T::WeightInfo::update_schedule())] pub fn update_schedule( origin: OriginFor, schedule: Schedule ) -> DispatchResultWithPostInfo { ensure_root(origin)?; if >::current_schedule().version > schedule.version { Err(Error::::InvalidScheduleVersion)? } Self::deposit_event(Event::ScheduleUpdated(schedule.version)); CurrentSchedule::put(schedule); Ok(().into()) } /// Makes a call to an account, optionally transferring some balance. /// /// * If the account is a smart-contract account, the associated code will be /// executed and any value will be transferred. /// * If the account is a regular account, any value will be transferred. /// * If no account exists and the call value is not less than `existential_deposit`, /// a regular account will be created and any value will be transferred. #[pallet::weight(T::WeightInfo::call(T::MaxCodeSize::get() / 1024).saturating_add(*gas_limit))] pub fn call( origin: OriginFor, dest: ::Source, #[pallet::compact] value: BalanceOf, #[pallet::compact] gas_limit: Weight, data: Vec ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; let mut gas_meter = GasMeter::new(gas_limit); let schedule = >::current_schedule(); let mut ctx = ExecutionContext::>::top_level(origin, &schedule); let (result, code_len) = match ctx.call(dest, value, &mut gas_meter, data) { Ok((output, len)) => (Ok(output), len), Err((err, len)) => (Err(err), len), }; gas_meter.into_dispatch_result(result, T::WeightInfo::call(code_len / 1024)) } /// Instantiates a new contract from the supplied `code` optionally transferring /// some balance. /// /// This is the only function that can deploy new code to the chain. /// /// # Parameters /// /// * `endowment`: The balance to transfer from the `origin` to the newly created contract. /// * `gas_limit`: The gas limit enforced when executing the constructor. /// * `code`: The contract code to deploy in raw bytes. /// * `data`: The input data to pass to the contract constructor. /// * `salt`: Used for the address derivation. See [`Pallet::contract_address`]. /// /// Instantiation is executed as follows: /// /// - The supplied `code` is instrumented, deployed, and a `code_hash` is created for that code. /// - If the `code_hash` already exists on the chain the underlying `code` will be shared. /// - The destination address is computed based on the sender, code_hash and the salt. /// - The smart-contract account is created at the computed address. /// - The `endowment` is transferred to the new account. /// - The `deploy` function is executed in the context of the newly-created account. #[pallet::weight( T::WeightInfo::instantiate_with_code( code.len() as u32 / 1024, salt.len() as u32 / 1024, ) .saturating_add(*gas_limit) )] pub fn instantiate_with_code( origin: OriginFor, #[pallet::compact] endowment: BalanceOf, #[pallet::compact] gas_limit: Weight, code: Vec, data: Vec, salt: Vec, ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let code_len = code.len() as u32; ensure!(code_len <= T::MaxCodeSize::get(), Error::::CodeTooLarge); let mut gas_meter = GasMeter::new(gas_limit); let schedule = >::current_schedule(); let executable = PrefabWasmModule::from_code(code, &schedule)?; let code_len = executable.code_len(); ensure!(code_len <= T::MaxCodeSize::get(), Error::::CodeTooLarge); let mut ctx = ExecutionContext::>::top_level(origin, &schedule); let result = ctx.instantiate(endowment, &mut gas_meter, executable, data, &salt) .map(|(_address, output)| output); gas_meter.into_dispatch_result( result, T::WeightInfo::instantiate_with_code(code_len / 1024, salt.len() as u32 / 1024) ) } /// Instantiates a contract from a previously deployed wasm binary. /// /// This function is identical to [`Self::instantiate_with_code`] but without the /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary /// must be supplied. #[pallet::weight( T::WeightInfo::instantiate(T::MaxCodeSize::get() / 1024, salt.len() as u32 / 1024) .saturating_add(*gas_limit) )] pub fn instantiate( origin: OriginFor, #[pallet::compact] endowment: BalanceOf, #[pallet::compact] gas_limit: Weight, code_hash: CodeHash, data: Vec, salt: Vec, ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let mut gas_meter = GasMeter::new(gas_limit); let schedule = >::current_schedule(); let executable = PrefabWasmModule::from_storage(code_hash, &schedule, &mut gas_meter)?; let mut ctx = ExecutionContext::>::top_level(origin, &schedule); let code_len = executable.code_len(); let result = ctx.instantiate(endowment, &mut gas_meter, executable, data, &salt) .map(|(_address, output)| output); gas_meter.into_dispatch_result( result, T::WeightInfo::instantiate(code_len / 1024, salt.len() as u32 / 1024), ) } /// Allows block producers to claim a small reward for evicting a contract. If a block /// producer fails to do so, a regular users will be allowed to claim the reward. /// /// In case of a successful eviction no fees are charged from the sender. However, the /// reward is capped by the total amount of rent that was payed by the contract while /// it was alive. /// /// If contract is not evicted as a result of this call, [`Error::ContractNotEvictable`] /// is returned and the sender is not eligible for the reward. #[pallet::weight(T::WeightInfo::claim_surcharge(T::MaxCodeSize::get() / 1024))] pub fn claim_surcharge( origin: OriginFor, dest: T::AccountId, aux_sender: Option ) -> DispatchResultWithPostInfo { let origin = origin.into(); let (signed, rewarded) = match (origin, aux_sender) { (Ok(frame_system::RawOrigin::Signed(account)), None) => { (true, account) }, (Ok(frame_system::RawOrigin::None), Some(aux_sender)) => { (false, aux_sender) }, _ => Err(Error::::InvalidSurchargeClaim)?, }; // Add some advantage for block producers (who send unsigned extrinsics) by // adding a handicap: for signed extrinsics we use a slightly older block number // for the eviction check. This can be viewed as if we pushed regular users back in past. let handicap = if signed { T::SignedClaimHandicap::get() } else { Zero::zero() }; // If poking the contract has lead to eviction of the contract, give out the rewards. match Rent::>::try_eviction(&dest, handicap)? { (Some(rent_payed), code_len) => { T::Currency::deposit_into_existing( &rewarded, T::SurchargeReward::get().min(rent_payed), ) .map(|_| PostDispatchInfo { actual_weight: Some(T::WeightInfo::claim_surcharge(code_len / 1024)), pays_fee: Pays::No, }) .map_err(Into::into) } (None, code_len) => Err(Error::::ContractNotEvictable.with_weight( T::WeightInfo::claim_surcharge(code_len / 1024) )), } } } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] #[pallet::metadata(T::AccountId = "AccountId", T::Hash = "Hash", BalanceOf = "Balance")] pub enum Event { /// Contract deployed by address at the specified address. \[deployer, contract\] Instantiated(T::AccountId, T::AccountId), /// Contract has been evicted and is now in tombstone state. \[contract\] Evicted(T::AccountId), /// Contract has been terminated without leaving a tombstone. /// \[contract, beneficiary\] /// /// # Params /// /// - `contract`: The contract that was terminated. /// - `beneficiary`: The account that received the contracts remaining balance. /// /// # Note /// /// The only way for a contract to be removed without a tombstone and emitting /// this event is by calling `seal_terminate`. Terminated(T::AccountId, T::AccountId), /// Restoration of a contract has been successful. /// \[restorer, dest, code_hash, rent_allowance\] /// /// # Params /// /// - `restorer`: Account ID of the restoring contract. /// - `dest`: Account ID of the restored contract. /// - `code_hash`: Code hash of the restored contract. /// - `rent_allowance`: Rent allowance of the restored contract. Restored(T::AccountId, T::AccountId, T::Hash, BalanceOf), /// Code with the specified hash has been stored. \[code_hash\] CodeStored(T::Hash), /// Triggered when the current schedule is updated. /// \[version\] /// /// # Params /// /// - `version`: The version of the newly set schedule. ScheduleUpdated(u32), /// A custom event emitted by the contract. /// \[contract, data\] /// /// # Params /// /// - `contract`: The contract that emitted the event. /// - `data`: Data supplied by the contract. Metadata generated during contract /// compilation is needed to decode it. ContractEmitted(T::AccountId, Vec), /// A code with the specified hash was removed. /// \[code_hash\] /// /// This happens when the last contract that uses this code hash was removed or evicted. CodeRemoved(T::Hash), } #[pallet::error] pub enum Error { /// A new schedule must have a greater version than the current one. InvalidScheduleVersion, /// An origin must be signed or inherent and auxiliary sender only provided on inherent. InvalidSurchargeClaim, /// Cannot restore from nonexisting or tombstone contract. InvalidSourceContract, /// Cannot restore to nonexisting or alive contract. InvalidDestinationContract, /// Tombstones don't match. InvalidTombstone, /// An origin TrieId written in the current block. InvalidContractOrigin, /// The executed contract exhausted its gas limit. OutOfGas, /// The output buffer supplied to a contract API call was too small. OutputBufferTooSmall, /// Performing the requested transfer would have brought the contract below /// the subsistence threshold. No transfer is allowed to do this in order to allow /// for a tombstone to be created. Use `seal_terminate` to remove a contract without /// leaving a tombstone behind. BelowSubsistenceThreshold, /// The newly created contract is below the subsistence threshold after executing /// its contructor. No contracts are allowed to exist below that threshold. NewContractNotFunded, /// Performing the requested transfer failed for a reason originating in the /// chosen currency implementation of the runtime. Most probably the balance is /// too low or locks are placed on it. TransferFailed, /// Performing a call was denied because the calling depth reached the limit /// of what is specified in the schedule. MaxCallDepthReached, /// The contract that was called is either no contract at all (a plain account) /// or is a tombstone. NotCallable, /// The code supplied to `instantiate_with_code` exceeds the limit specified in the /// current schedule. CodeTooLarge, /// No code could be found at the supplied code hash. CodeNotFound, /// A buffer outside of sandbox memory was passed to a contract API function. OutOfBounds, /// Input passed to a contract API function failed to decode as expected type. DecodingFailed, /// Contract trapped during execution. ContractTrapped, /// The size defined in `T::MaxValueSize` was exceeded. ValueTooLarge, /// The action performed is not allowed while the contract performing it is already /// on the call stack. Those actions are contract self destruction and restoration /// of a tombstone. ReentranceDenied, /// `seal_input` was called twice from the same contract execution context. InputAlreadyRead, /// The subject passed to `seal_random` exceeds the limit. RandomSubjectTooLong, /// The amount of topics passed to `seal_deposit_events` exceeds the limit. TooManyTopics, /// The topics passed to `seal_deposit_events` contains at least one duplicate. DuplicateTopics, /// The chain does not provide a chain extension. Calling the chain extension results /// in this error. Note that this usually shouldn't happen as deploying such contracts /// is rejected. NoChainExtension, /// Removal of a contract failed because the deletion queue is full. /// /// This can happen when either calling [`Pallet::claim_surcharge`] or `seal_terminate`. /// The queue is filled by deleting contracts and emptied by a fixed amount each block. /// Trying again during another block is the only way to resolve this issue. DeletionQueueFull, /// A contract could not be evicted because it has enough balance to pay rent. /// /// This can be returned from [`Pallet::claim_surcharge`] because the target /// contract has enough balance to pay for its rent. ContractNotEvictable, /// A storage modification exhausted the 32bit type that holds the storage size. /// /// This can either happen when the accumulated storage in bytes is too large or /// when number of storage items is too large. StorageExhausted, /// A contract with the same AccountId already exists. DuplicateContract, } /// Current cost schedule for contracts. #[pallet::storage] #[pallet::getter(fn current_schedule)] pub(super) type CurrentSchedule = StorageValue<_, Schedule, ValueQuery>; /// A mapping from an original code hash to the original code, untouched by instrumentation. #[pallet::storage] pub type PristineCode = StorageMap<_, Identity, CodeHash, Vec>; /// A mapping between an original code hash and instrumented wasm code, ready for execution. #[pallet::storage] pub type CodeStorage = StorageMap<_, Identity, CodeHash, PrefabWasmModule>; /// The subtrie counter. #[pallet::storage] pub type AccountCounter = StorageValue<_, u64, ValueQuery>; /// The code associated with a given account. /// /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] pub type ContractInfoOf = StorageMap<_, Twox64Concat, T::AccountId, ContractInfo>; /// Evicted contracts that await child trie deletion. /// /// Child trie deletion is a heavy operation depending on the amount of storage items /// stored in said trie. Therefore this operation is performed lazily in `on_initialize`. #[pallet::storage] pub type DeletionQueue = StorageValue<_, Vec, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { #[doc = "Current cost schedule for contracts."] pub current_schedule: Schedule, } #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { Self { current_schedule: Default::default(), } } } #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { >::put(&self.current_schedule); } } } impl Pallet where T::AccountId: UncheckedFrom + AsRef<[u8]>, { /// Perform a call to a specified contract. /// /// This function is similar to `Self::call`, but doesn't perform any address lookups and better /// suitable for calling directly from Rust. /// /// It returns the execution result and the amount of used weight. pub fn bare_call( origin: T::AccountId, dest: T::AccountId, value: BalanceOf, gas_limit: Weight, input_data: Vec, ) -> ContractExecResult { let mut gas_meter = GasMeter::new(gas_limit); let schedule = >::current_schedule(); let mut ctx = ExecutionContext::>::top_level(origin, &schedule); let result = ctx.call(dest, value, &mut gas_meter, input_data); let gas_consumed = gas_meter.gas_spent(); ContractExecResult { exec_result: result.map(|r| r.0).map_err(|r| r.0), gas_consumed, } } /// Query storage of a specified contract under a specified key. pub fn get_storage(address: T::AccountId, key: [u8; 32]) -> GetStorageResult { let contract_info = ContractInfoOf::::get(&address) .ok_or(ContractAccessError::DoesntExist)? .get_alive() .ok_or(ContractAccessError::IsTombstone)?; let maybe_value = Storage::::read(&contract_info.trie_id, &key); Ok(maybe_value) } /// Query how many blocks the contract stays alive given that the amount endowment /// and consumed storage does not change. pub fn rent_projection(address: T::AccountId) -> RentProjectionResult { Rent::>::compute_projection(&address) } /// Determine the address of a contract, /// /// This is the address generation function used by contract instantiation. Its result /// is only dependend on its inputs. It can therefore be used to reliably predict the /// address of a contract. This is akin to the formular of eth's CREATE2 opcode. There /// is no CREATE equivalent because CREATE2 is strictly more powerful. /// /// Formula: `hash(deploying_address ++ code_hash ++ salt)` pub fn contract_address( deploying_address: &T::AccountId, code_hash: &CodeHash, salt: &[u8], ) -> T::AccountId { let buf: Vec<_> = deploying_address.as_ref().iter() .chain(code_hash.as_ref()) .chain(salt) .cloned() .collect(); UncheckedFrom::unchecked_from(T::Hashing::hash(&buf)) } /// Subsistence threshold is the extension of the minimum balance (aka existential deposit) /// by the tombstone deposit, required for leaving a tombstone. /// /// Rent or any contract initiated balance transfer mechanism cannot make the balance lower /// than the subsistence threshold in order to guarantee that a tombstone is created. /// /// The only way to completely kill a contract without a tombstone is calling `seal_terminate`. pub fn subsistence_threshold() -> BalanceOf { T::Currency::minimum_balance().saturating_add(T::TombstoneDeposit::get()) } /// Store code for benchmarks which does not check nor instrument the code. #[cfg(feature = "runtime-benchmarks")] fn store_code_raw(code: Vec) -> frame_support::dispatch::DispatchResult { let schedule = >::current_schedule(); PrefabWasmModule::store_code_unchecked(code, &schedule)?; Ok(()) } /// This exists so that benchmarks can determine the weight of running an instrumentation. #[cfg(feature = "runtime-benchmarks")] fn reinstrument_module( module: &mut PrefabWasmModule, schedule: &Schedule ) -> frame_support::dispatch::DispatchResult { self::wasm::reinstrument(module, schedule) } } /// Information for managing an account and its sub trie abstraction. /// This is the required info to cache for an account #[derive(Encode, Decode, RuntimeDebug)] pub enum ContractInfo { Alive(AliveContractInfo), Tombstone(TombstoneContractInfo), } impl ContractInfo { /// If contract is alive then return some alive info pub fn get_alive(self) -> Option> { if let ContractInfo::Alive(alive) = self { Some(alive) } else { None } } /// If contract is alive then return some reference to alive info pub fn as_alive(&self) -> Option<&AliveContractInfo> { if let ContractInfo::Alive(ref alive) = self { Some(alive) } else { None } } /// If contract is alive then return some mutable reference to alive info pub fn as_alive_mut(&mut self) -> Option<&mut AliveContractInfo> { if let ContractInfo::Alive(ref mut alive) = self { Some(alive) } else { None } } /// If contract is tombstone then return some tombstone info pub fn get_tombstone(self) -> Option> { if let ContractInfo::Tombstone(tombstone) = self { Some(tombstone) } else { None } } /// If contract is tombstone then return some reference to tombstone info pub fn as_tombstone(&self) -> Option<&TombstoneContractInfo> { if let ContractInfo::Tombstone(ref tombstone) = self { Some(tombstone) } else { None } } /// If contract is tombstone then return some mutable reference to tombstone info pub fn as_tombstone_mut(&mut self) -> Option<&mut TombstoneContractInfo> { if let ContractInfo::Tombstone(ref mut tombstone) = self { Some(tombstone) } else { None } } } /// Information for managing an account and its sub trie abstraction. /// This is the required info to cache for an account. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] pub struct RawAliveContractInfo { /// Unique ID for the subtree encoded as a bytes vector. pub trie_id: TrieId, /// The total number of bytes used by this contract. /// /// It is a sum of each key-value pair stored by this contract. pub storage_size: u32, /// The total number of key-value pairs in storage of this contract. pub pair_count: u32, /// The code associated with a given account. pub code_hash: CodeHash, /// Pay rent at most up to this value. pub rent_allowance: Balance, /// The amount of rent that was payed by the contract over its whole lifetime. /// /// A restored contract starts with a value of zero just like a new contract. pub rent_payed: Balance, /// Last block rent has been payed. pub deduct_block: BlockNumber, /// Last block child storage has been written. pub last_write: Option, /// This field is reserved for future evolution of format. pub _reserved: Option<()>, } impl RawAliveContractInfo { /// Associated child trie unique id is built from the hash part of the trie id. pub fn child_trie_info(&self) -> ChildInfo { child_trie_info(&self.trie_id[..]) } } /// Associated child trie unique id is built from the hash part of the trie id. pub(crate) fn child_trie_info(trie_id: &[u8]) -> ChildInfo { ChildInfo::new_default(trie_id) } #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug)] pub struct RawTombstoneContractInfo(H, PhantomData); impl RawTombstoneContractInfo where H: Member + MaybeSerializeDeserialize+ Debug + AsRef<[u8]> + AsMut<[u8]> + Copy + Default + sp_std::hash::Hash + Codec, Hasher: Hash, { fn new(storage_root: &[u8], code_hash: H) -> Self { let mut buf = Vec::new(); storage_root.using_encoded(|encoded| buf.extend_from_slice(encoded)); buf.extend_from_slice(code_hash.as_ref()); RawTombstoneContractInfo(::hash(&buf[..]), PhantomData) } } impl From> for ContractInfo { fn from(alive_info: AliveContractInfo) -> Self { Self::Alive(alive_info) } }