diff --git a/substrate/bin/node/executor/tests/basic.rs b/substrate/bin/node/executor/tests/basic.rs index 3e3b2d1eaaf3f0e1c2fd515b619e7272d6167be2..c18f81bdc07d5a0a4920bc8f907e0e1aaba18671 100644 --- a/substrate/bin/node/executor/tests/basic.rs +++ b/substrate/bin/node/executor/tests/basic.rs @@ -17,7 +17,6 @@ use codec::{Encode, Decode, Joiner}; use frame_support::{ - StorageMap, traits::Currency, weights::{GetDispatchInfo, DispatchInfo, DispatchClass}, }; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index b52b24ed01bc75adba531236c0cf1b50a76801de..c8d7717b4c8fb1bbe81bad9f778e2a9b0d93772e 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -71,7 +71,7 @@ pub use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment, Currency use pallet_session::{historical as pallet_session_historical}; use sp_inherents::{InherentData, CheckInherentsResult}; use static_assertions::const_assert; -use pallet_contracts::WeightInfo; +use pallet_contracts::weights::WeightInfo; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; diff --git a/substrate/frame/contracts/src/benchmarking/mod.rs b/substrate/frame/contracts/src/benchmarking/mod.rs index b6ff4c04ff7ec4c7b268bad9258e1316b1abbfa4..d01a2bce2c27b6bf837ec4dd69e099e9a2f7f5fe 100644 --- a/substrate/frame/contracts/src/benchmarking/mod.rs +++ b/substrate/frame/contracts/src/benchmarking/mod.rs @@ -42,6 +42,7 @@ use parity_wasm::elements::{Instruction, ValueType, BlockType}; use sp_runtime::traits::{Hash, Bounded, Zero}; use sp_std::{default::Default, convert::{TryInto}, vec::Vec, vec}; use pallet_contracts_primitives::RentProjection; +use frame_support::weights::Weight; /// How many batches we do per API benchmark. const API_BENCHMARK_BATCHES: u32 = 20; diff --git a/substrate/frame/contracts/src/chain_extension.rs b/substrate/frame/contracts/src/chain_extension.rs index ef6e034791753cc22a69077a8159bb84a7ee5166..dc6e9771775ca7744da448b7b46039072f0ea301 100644 --- a/substrate/frame/contracts/src/chain_extension.rs +++ b/substrate/frame/contracts/src/chain_extension.rs @@ -18,7 +18,7 @@ //! A mechanism for runtime authors to augment the functionality of contracts. //! //! The runtime is able to call into any contract and retrieve the result using -//! [`bare_call`](crate::Module::bare_call). This already allows customization of runtime +//! [`bare_call`](crate::Pallet::bare_call). This already allows customization of runtime //! behaviour by user generated code (contracts). However, often it is more straightforward //! to allow the reverse behaviour: The contract calls into the runtime. We call the latter //! one a "chain extension" because it allows the chain to extend the set of functions that are @@ -37,7 +37,7 @@ //! [`charge_weight`](Environment::charge_weight) function must be called **before** //! carrying out any action that causes the consumption of the chargeable weight. //! It cannot be overstated how delicate of a process the creation of a chain extension -//! is. Check whether using [`bare_call`](crate::Module::bare_call) suffices for the +//! is. Check whether using [`bare_call`](crate::Pallet::bare_call) suffices for the //! use case at hand. //! //! # Benchmarking @@ -328,7 +328,7 @@ where /// /// If the contract supplied buffer is smaller than the passed `buffer` an `Err` is returned. /// If `allow_skip` is set to true the contract is allowed to skip the copying of the buffer - /// by supplying the guard value of [`u32::max_value()`] as `out_ptr`. The + /// by supplying the guard value of `u32::max_value()` as `out_ptr`. The /// `weight_per_byte` is only charged when the write actually happens and is not skipped or /// failed due to a too small output buffer. pub fn write( diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index bf9efddc6166f349992a59851281fb9e0631e9e6..745384a8674bc51e5273e6c54ee6303faecded58 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::{ - CodeHash, Event, RawEvent, Config, Module as Contracts, + CodeHash, Event, Config, Module as Contracts, TrieId, BalanceOf, ContractInfo, gas::GasMeter, rent::Rent, storage::{self, Storage}, Error, ContractInfoOf, Schedule, }; @@ -30,7 +30,7 @@ use frame_support::{ dispatch::{DispatchResult, DispatchError}, traits::{ExistenceRequirement, Currency, Time, Randomness, Get}, weights::Weight, - ensure, StorageMap, + ensure, }; use pallet_contracts_primitives::{ErrorOrigin, ExecError, ExecReturnValue, ExecResult, ReturnFlags}; @@ -57,7 +57,11 @@ pub enum TransactorKind { /// /// This interface is specialized to an account of the executing code, so all /// operations are implicitly performed on that account. -pub trait Ext { +/// +/// # Note +/// +/// This trait is sealed and cannot be implemented by downstream crates. +pub trait Ext: sealing::Sealed { type T: Config; /// Returns the storage entry of the executing account by the given `key`. @@ -446,7 +450,7 @@ where .ok_or(Error::<T>::NewContractNotFunded)?; // Deposit an instantiation event. - deposit_event::<T>(vec![], RawEvent::Instantiated(caller.clone(), dest.clone())); + deposit_event::<T>(vec![], Event::Instantiated(caller.clone(), dest.clone())); Ok(output) }); @@ -664,7 +668,7 @@ where if let Some(ContractInfo::Alive(info)) = ContractInfoOf::<T>::take(&self_id) { Storage::<T>::queue_trie_for_deletion(&info).map_err(|e| (e, 0))?; let code_len = E::remove_user(info.code_hash); - Contracts::<T>::deposit_event(RawEvent::Terminated(self_id, beneficiary.clone())); + Contracts::<T>::deposit_event(Event::Terminated(self_id, beneficiary.clone())); Ok(code_len) } else { panic!( @@ -708,7 +712,7 @@ where if let Ok(_) = result { deposit_event::<Self::T>( vec![], - RawEvent::Restored( + Event::Restored( self.ctx.self_account.clone(), dest, code_hash, @@ -754,7 +758,7 @@ where fn deposit_event(&mut self, topics: Vec<T::Hash>, data: Vec<u8>) { deposit_event::<Self::T>( topics, - RawEvent::ContractEmitted(self.ctx.self_account.clone(), data) + Event::ContractEmitted(self.ctx.self_account.clone(), data) ); } @@ -799,6 +803,20 @@ fn deposit_event<T: Config>( ) } +mod sealing { + use super::*; + + pub trait Sealed {} + + impl<'a, 'b: 'a, T: Config, E> Sealed for CallContext<'a, 'b, T, E> {} + + #[cfg(test)] + impl Sealed for crate::wasm::MockExt {} + + #[cfg(test)] + impl Sealed for &mut crate::wasm::MockExt {} +} + /// These tests exercise the executive layer. /// /// In these tests the VM/loader are mocked. Instead of dealing with wasm bytecode they use simple closures. @@ -809,13 +827,12 @@ mod tests { use super::*; use crate::{ gas::GasMeter, tests::{ExtBuilder, Test, Event as MetaEvent}, - gas::Gas, storage::Storage, tests::{ ALICE, BOB, CHARLIE, test_utils::{place_contract, set_balance, get_balance}, }, - Error, + Error, Weight, }; use sp_runtime::DispatchError; use assert_matches::assert_matches; @@ -823,7 +840,7 @@ mod tests { type MockContext<'a> = ExecutionContext<'a, Test, MockExecutable>; - const GAS_LIMIT: Gas = 10_000_000_000; + const GAS_LIMIT: Weight = 10_000_000_000; thread_local! { static LOADER: RefCell<MockLoader> = RefCell::new(MockLoader::default()); @@ -1334,7 +1351,7 @@ mod tests { // there are instantiation event. assert_eq!(Storage::<Test>::code_hash(&instantiated_contract_address).unwrap(), dummy_ch); assert_eq!(&events(), &[ - RawEvent::Instantiated(ALICE, instantiated_contract_address) + Event::Instantiated(ALICE, instantiated_contract_address) ]); }); } @@ -1410,7 +1427,7 @@ mod tests { // there are instantiation event. assert_eq!(Storage::<Test>::code_hash(&instantiated_contract_address).unwrap(), dummy_ch); assert_eq!(&events(), &[ - RawEvent::Instantiated(BOB, instantiated_contract_address) + Event::Instantiated(BOB, instantiated_contract_address) ]); }); } diff --git a/substrate/frame/contracts/src/gas.rs b/substrate/frame/contracts/src/gas.rs index 2737f351a50de75c902c27dc946a6f896690fb58..80e608b217bd32377125c8e847d7ccfd19d228dd 100644 --- a/substrate/frame/contracts/src/gas.rs +++ b/substrate/frame/contracts/src/gas.rs @@ -30,14 +30,11 @@ use sp_core::crypto::UncheckedFrom; #[cfg(test)] use std::{any::Any, fmt::Debug}; -// Gas is essentially the same as weight. It is a 1 to 1 correspondence. -pub type Gas = Weight; - #[derive(Debug, PartialEq, Eq)] -pub struct ChargedAmount(Gas); +pub struct ChargedAmount(Weight); impl ChargedAmount { - pub fn amount(&self) -> Gas { + pub fn amount(&self) -> Weight { self.0 } } @@ -72,7 +69,7 @@ pub trait Token<T: Config>: Copy + Clone + TestAuxiliaries { /// That said, implementors of this function still can run into overflows /// while calculating the amount. In this case it is ok to use saturating operations /// since on overflow they will return `max_value` which should consume all gas. - fn calculate_amount(&self, metadata: &Self::Metadata) -> Gas; + fn calculate_amount(&self, metadata: &Self::Metadata) -> Weight; } /// A wrapper around a type-erased trait object of what used to be a `Token`. @@ -83,9 +80,9 @@ pub struct ErasedToken { } pub struct GasMeter<T: Config> { - gas_limit: Gas, + gas_limit: Weight, /// Amount of gas left from initial gas limit. Can reach zero. - gas_left: Gas, + gas_left: Weight, _phantom: PhantomData<T>, #[cfg(test)] tokens: Vec<ErasedToken>, @@ -95,7 +92,7 @@ impl<T: Config> GasMeter<T> where T::AccountId: UncheckedFrom<<T as frame_system::Config>::Hash> + AsRef<[u8]> { - pub fn new(gas_limit: Gas) -> Self { + pub fn new(gas_limit: Weight) -> Self { GasMeter { gas_limit, gas_left: gas_limit, @@ -177,7 +174,7 @@ where /// All unused gas in the nested gas meter is returned to this gas meter. pub fn with_nested<R, F: FnOnce(Option<&mut GasMeter<T>>) -> R>( &mut self, - amount: Gas, + amount: Weight, f: F, ) -> R { // NOTE that it is ok to allocate all available gas since it still ensured @@ -197,12 +194,12 @@ where } /// Returns how much gas was used. - pub fn gas_spent(&self) -> Gas { + pub fn gas_spent(&self) -> Weight { self.gas_limit - self.gas_left } /// Returns how much gas left from the initial budget. - pub fn gas_left(&self) -> Gas { + pub fn gas_left(&self) -> Weight { self.gas_left } @@ -230,49 +227,48 @@ where } } -/// A simple utility macro that helps to match against a -/// list of tokens. -#[macro_export] -macro_rules! match_tokens { - ($tokens_iter:ident,) => { - }; - ($tokens_iter:ident, $x:expr, $($rest:tt)*) => { - { - let next = ($tokens_iter).next().unwrap(); - let pattern = $x; - - // Note that we don't specify the type name directly in this macro, - // we only have some expression $x of some type. At the same time, we - // have an iterator of Box<dyn Any> and to downcast we need to specify - // the type which we want downcast to. - // - // So what we do is we assign `_pattern_typed_next_ref` to a variable which has - // the required type. - // - // Then we make `_pattern_typed_next_ref = token.downcast_ref()`. This makes - // rustc infer the type `T` (in `downcast_ref<T: Any>`) to be the same as in $x. - - let mut _pattern_typed_next_ref = &pattern; - _pattern_typed_next_ref = match next.token.downcast_ref() { - Some(p) => { - assert_eq!(p, &pattern); - p - } - None => { - panic!("expected type {} got {}", stringify!($x), next.description); - } - }; - } - - match_tokens!($tokens_iter, $($rest)*); - }; -} - #[cfg(test)] mod tests { use super::{GasMeter, Token}; use crate::tests::Test; + /// A simple utility macro that helps to match against a + /// list of tokens. + macro_rules! match_tokens { + ($tokens_iter:ident,) => { + }; + ($tokens_iter:ident, $x:expr, $($rest:tt)*) => { + { + let next = ($tokens_iter).next().unwrap(); + let pattern = $x; + + // Note that we don't specify the type name directly in this macro, + // we only have some expression $x of some type. At the same time, we + // have an iterator of Box<dyn Any> and to downcast we need to specify + // the type which we want downcast to. + // + // So what we do is we assign `_pattern_typed_next_ref` to a variable which has + // the required type. + // + // Then we make `_pattern_typed_next_ref = token.downcast_ref()`. This makes + // rustc infer the type `T` (in `downcast_ref<T: Any>`) to be the same as in $x. + + let mut _pattern_typed_next_ref = &pattern; + _pattern_typed_next_ref = match next.token.downcast_ref() { + Some(p) => { + assert_eq!(p, &pattern); + p + } + None => { + panic!("expected type {} got {}", stringify!($x), next.description); + } + }; + } + + match_tokens!($tokens_iter, $($rest)*); + }; + } + /// A trivial token that charges the specified number of gas units. #[derive(Copy, Clone, PartialEq, Eq, Debug)] struct SimpleToken(u64); diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 4e56230e93f3a046037660744d855115846df995..1f21a59e61584bdf68a74f6531c156b631ab08c5 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -98,368 +98,80 @@ pub mod weights; mod tests; pub use crate::{ - gas::{Gas, GasMeter}, - wasm::{ReturnCode as RuntimeReturnCode, PrefabWasmModule}, - weights::WeightInfo, + wasm::PrefabWasmModule, schedule::{Schedule, HostFnWeights, InstructionWeights, Limits}, + pallet::*, }; use crate::{ + gas::GasMeter, exec::{ExecutionContext, Executable}, rent::Rent, - storage::Storage, + 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, Zero, MaybeSerializeDeserialize, Member, Convert, Saturating, + Hash, StaticLookup, MaybeSerializeDeserialize, Member, Convert, Saturating, Zero, }, RuntimeDebug, Perbill, }; use frame_support::{ - decl_module, decl_event, decl_storage, decl_error, ensure, storage::child::ChildInfo, - dispatch::{DispatchResult, DispatchResultWithPostInfo}, traits::{OnUnbalanced, Currency, Get, Time, Randomness}, - weights::Pays, + weights::{Weight, PostDispatchInfo, WithPostDispatchInfo}, }; -use frame_system::{ensure_signed, ensure_root, Module as System}; +use frame_system::Module as System; use pallet_contracts_primitives::{ RentProjectionResult, GetStorageResult, ContractAccessError, ContractExecResult, }; -use frame_support::weights::{Weight, PostDispatchInfo, WithPostDispatchInfo}; pub type CodeHash<T> = <T as frame_system::Config>::Hash; pub type TrieId = Vec<u8>; - -/// 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<T: Config> { - Alive(AliveContractInfo<T>), - Tombstone(TombstoneContractInfo<T>), -} - -impl<T: Config> ContractInfo<T> { - /// If contract is alive then return some alive info - pub fn get_alive(self) -> Option<AliveContractInfo<T>> { - 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<T>> { - 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<T>> { - 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<TombstoneContractInfo<T>> { - 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<T>> { - 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<T>> { - if let ContractInfo::Tombstone(ref mut tombstone) = self { - Some(tombstone) - } else { - None - } - } -} - -pub type AliveContractInfo<T> = - RawAliveContractInfo<CodeHash<T>, BalanceOf<T>, <T as frame_system::Config>::BlockNumber>; - -/// 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<CodeHash, Balance, BlockNumber> { - /// 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<BlockNumber>, -} - -impl<CodeHash, Balance, BlockNumber> RawAliveContractInfo<CodeHash, Balance, BlockNumber> { - /// 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) -} - -pub type TombstoneContractInfo<T> = - RawTombstoneContractInfo<<T as frame_system::Config>::Hash, <T as frame_system::Config>::Hashing>; - -#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug)] -pub struct RawTombstoneContractInfo<H, Hasher>(H, PhantomData<Hasher>); - -impl<H, Hasher> RawTombstoneContractInfo<H, Hasher> -where - H: Member + MaybeSerializeDeserialize+ Debug - + AsRef<[u8]> + AsMut<[u8]> + Copy + Default - + sp_std::hash::Hash + Codec, - Hasher: Hash<Output=H>, -{ - 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(<Hasher as Hash>::hash(&buf[..]), PhantomData) - } -} - -impl<T: Config> From<AliveContractInfo<T>> for ContractInfo<T> { - fn from(alive_info: AliveContractInfo<T>) -> Self { - Self::Alive(alive_info) - } -} - pub type BalanceOf<T> = <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance; pub type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::NegativeImbalance; +pub type AliveContractInfo<T> = + RawAliveContractInfo<CodeHash<T>, BalanceOf<T>, <T as frame_system::Config>::BlockNumber>; +pub type TombstoneContractInfo<T> = + RawTombstoneContractInfo<<T as frame_system::Config>::Hash, <T as frame_system::Config>::Hashing>; -pub trait Config: frame_system::Config { - type Time: Time; - type Randomness: Randomness<Self::Hash>; - - /// The currency in which fees are paid and contract balances are held. - type Currency: Currency<Self::AccountId>; - - /// The overarching event type. - type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>; - - /// Handler for rent payments. - type RentPayment: OnUnbalanced<NegativeImbalanceOf<Self>>; - - /// 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 - type SignedClaimHandicap: Get<Self::BlockNumber>; - - /// The minimum amount required to generate a tombstone. - type TombstoneDeposit: Get<BalanceOf<Self>>; - - /// 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. - type DepositPerContract: Get<BalanceOf<Self>>; - - /// 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. - type DepositPerStorageByte: Get<BalanceOf<Self>>; - - /// 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. - type DepositPerStorageItem: Get<BalanceOf<Self>>; - - /// 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. - type RentFraction: Get<Perbill>; - - /// Reward that is received by the party whose touch has led - /// to removal of a contract. - type SurchargeReward: Get<BalanceOf<Self>>; - - /// The maximum nesting level of a call/instantiate stack. - type MaxDepth: Get<u32>; - - /// The maximum size of a storage value and event payload in bytes. - type MaxValueSize: Get<u32>; - - /// Used to answer contracts's queries regarding the current weight price. This is **not** - /// used to calculate the actual fee and is only for informational purposes. - type WeightPrice: Convert<Weight, BalanceOf<Self>>; - - /// 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<Self>; +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use super::*; - /// The maximum number of tries that can be queued for deletion. - type DeletionQueueDepth: Get<u32>; + #[pallet::config] + pub trait Config: frame_system::Config { + /// The time implementation used to supply timestamps to conntracts through `seal_now`. + type Time: Time; - /// The maximum amount of weight that can be consumed per block for lazy trie removal. - type DeletionWeightLimit: Get<Weight>; + /// The generator used to supply randomness to contracts through `seal_random`. + type Randomness: Randomness<Self::Hash>; - /// 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. - type MaxCodeSize: Get<u32>; -} + /// The currency in which fees are paid and contract balances are held. + type Currency: Currency<Self::AccountId>; -decl_error! { - /// Error for the contracts module. - pub enum Error for Module<T: Config> - where - T::AccountId: UncheckedFrom<T::Hash>, - T::AccountId: AsRef<[u8]>, - { - /// 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 [`Module::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 [`Module::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, - } -} + /// The overarching event type. + type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>; -decl_module! { - /// Contracts module. - pub struct Module<T: Config> for enum Call - where - origin: T::Origin, - T::AccountId: UncheckedFrom<T::Hash>, - T::AccountId: AsRef<[u8]>, - { - type Error = Error<T>; + /// Handler for rent payments. + type RentPayment: OnUnbalanced<NegativeImbalanceOf<Self>>; /// 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 - const SignedClaimHandicap: T::BlockNumber = T::SignedClaimHandicap::get(); + #[pallet::constant] + type SignedClaimHandicap: Get<Self::BlockNumber>; /// The minimum amount required to generate a tombstone. - const TombstoneDeposit: BalanceOf<T> = T::TombstoneDeposit::get(); + #[pallet::constant] + type TombstoneDeposit: Get<BalanceOf<Self>>; /// The balance every contract needs to deposit to stay alive indefinitely. /// @@ -469,7 +181,8 @@ decl_module! { /// /// 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. - const DepositPerContract: BalanceOf<T> = T::DepositPerContract::get(); + #[pallet::constant] + type DepositPerContract: Get<BalanceOf<Self>>; /// The balance a contract needs to deposit per storage byte to stay alive indefinitely. /// @@ -477,40 +190,73 @@ decl_module! { /// 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. - const DepositPerStorageByte: BalanceOf<T> = T::DepositPerStorageByte::get(); + #[pallet::constant] + type DepositPerStorageByte: Get<BalanceOf<Self>>; /// 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. - const DepositPerStorageItem: BalanceOf<T> = T::DepositPerStorageItem::get(); + #[pallet::constant] + type DepositPerStorageItem: Get<BalanceOf<Self>>; /// 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. - const RentFraction: Perbill = T::RentFraction::get(); + #[pallet::constant] + type RentFraction: Get<Perbill>; /// Reward that is received by the party whose touch has led /// to removal of a contract. - const SurchargeReward: BalanceOf<T> = T::SurchargeReward::get(); + #[pallet::constant] + type SurchargeReward: Get<BalanceOf<Self>>; + + /// The maximum nesting level of a call/instantiate stack. + #[pallet::constant] + type MaxDepth: Get<u32>; + + /// The maximum size of a storage value and event payload in bytes. + #[pallet::constant] + type MaxValueSize: Get<u32>; - /// The maximum nesting level of a call/instantiate stack. A reasonable default - /// value is 100. - const MaxDepth: u32 = T::MaxDepth::get(); + /// Used to answer contracts's queries regarding the current weight price. This is **not** + /// used to calculate the actual fee and is only for informational purposes. + type WeightPrice: Convert<Weight, BalanceOf<Self>>; - /// The maximum size of a storage value in bytes. A reasonable default is 16 KiB. - const MaxValueSize: u32 = T::MaxValueSize::get(); + /// 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<Self>; /// The maximum number of tries that can be queued for deletion. - const DeletionQueueDepth: u32 = T::DeletionQueueDepth::get(); + #[pallet::constant] + type DeletionQueueDepth: Get<u32>; /// The maximum amount of weight that can be consumed per block for lazy trie removal. - const DeletionWeightLimit: Weight = T::DeletionWeightLimit::get(); + #[pallet::constant] + type DeletionWeightLimit: Get<Weight>; + + /// 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<u32>; + } - fn deposit_event() = default; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet<T>(PhantomData<T>); - fn on_initialize() -> Weight { + #[pallet::hooks] + impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> + where + T::AccountId: UncheckedFrom<T::Hash>, + 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 @@ -519,21 +265,29 @@ decl_module! { Storage::<T>::process_deletion_queue_batch(weight_limit) .saturating_add(T::WeightInfo::on_initialize()) } + } + #[pallet::call] + impl<T: Config> Pallet<T> + where + T::AccountId: UncheckedFrom<T::Hash>, + T::AccountId: AsRef<[u8]>, + { /// Updates the schedule for metering contracts. /// /// The schedule must have a greater version than the stored schedule. - #[weight = T::WeightInfo::update_schedule()] - pub fn update_schedule(origin, schedule: Schedule<T>) -> DispatchResult { + #[pallet::weight(T::WeightInfo::update_schedule())] + pub fn update_schedule( + origin: OriginFor<T>, + schedule: Schedule<T> + ) -> DispatchResultWithPostInfo { ensure_root(origin)?; if <Module<T>>::current_schedule().version >= schedule.version { Err(Error::<T>::InvalidScheduleVersion)? } - - Self::deposit_event(RawEvent::ScheduleUpdated(schedule.version)); + Self::deposit_event(Event::ScheduleUpdated(schedule.version)); CurrentSchedule::put(schedule); - - Ok(()) + Ok(().into()) } /// Makes a call to an account, optionally transferring some balance. @@ -543,12 +297,12 @@ decl_module! { /// * 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. - #[weight = T::WeightInfo::call(T::MaxCodeSize::get() / 1024).saturating_add(*gas_limit)] + #[pallet::weight(T::WeightInfo::call(T::MaxCodeSize::get() / 1024).saturating_add(*gas_limit))] pub fn call( - origin, + origin: OriginFor<T>, dest: <T::Lookup as StaticLookup>::Source, - #[compact] value: BalanceOf<T>, - #[compact] gas_limit: Gas, + #[pallet::compact] value: BalanceOf<T>, + #[pallet::compact] gas_limit: Weight, data: Vec<u8> ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; @@ -584,17 +338,17 @@ decl_module! { /// - 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. - #[weight = + #[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, - #[compact] endowment: BalanceOf<T>, - #[compact] gas_limit: Gas, + origin: OriginFor<T>, + #[pallet::compact] endowment: BalanceOf<T>, + #[pallet::compact] gas_limit: Weight, code: Vec<u8>, data: Vec<u8>, salt: Vec<u8>, @@ -618,89 +372,289 @@ decl_module! { /// 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. - #[weight = - T::WeightInfo::instantiate(T::MaxCodeSize::get() / 1024, salt.len() as u32 / 1024) - .saturating_add(*gas_limit) - ] - pub fn instantiate( - origin, - #[compact] endowment: BalanceOf<T>, - #[compact] gas_limit: Gas, - code_hash: CodeHash<T>, - data: Vec<u8>, - salt: Vec<u8>, - ) -> DispatchResultWithPostInfo { - let origin = ensure_signed(origin)?; - let mut gas_meter = GasMeter::new(gas_limit); - let schedule = <Module<T>>::current_schedule(); - let executable = PrefabWasmModule::from_storage(code_hash, &schedule, &mut gas_meter)?; - let mut ctx = ExecutionContext::<T, PrefabWasmModule<T>>::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. + /// 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<T>, + #[pallet::compact] endowment: BalanceOf<T>, + #[pallet::compact] gas_limit: Weight, + code_hash: CodeHash<T>, + data: Vec<u8>, + salt: Vec<u8>, + ) -> DispatchResultWithPostInfo { + let origin = ensure_signed(origin)?; + let mut gas_meter = GasMeter::new(gas_limit); + let schedule = <Module<T>>::current_schedule(); + let executable = PrefabWasmModule::from_storage(code_hash, &schedule, &mut gas_meter)?; + let mut ctx = ExecutionContext::<T, PrefabWasmModule<T>>::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<T>, + dest: T::AccountId, + aux_sender: Option<T::AccountId> + ) -> 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::<T>::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::<T, PrefabWasmModule<T>>::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::<T>::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<T> = "Balance")] + pub enum Event<T: Config> { + /// 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<T>), + + /// 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<u8>), + + /// 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<T> { + /// 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. /// - /// 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. + /// 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. /// - /// If contract is not evicted as a result of this call, [`Error::ContractNotEvictable`] - /// is returned and the sender is not eligible for the reward. - #[weight = T::WeightInfo::claim_surcharge(T::MaxCodeSize::get() / 1024)] - pub fn claim_surcharge( - origin, - dest: T::AccountId, - aux_sender: Option<T::AccountId> - ) -> 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::<T>::InvalidSurchargeClaim)?, - }; + /// 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, + } - // 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() - }; + /// Current cost schedule for contracts. + #[pallet::storage] + #[pallet::getter(fn current_schedule)] + pub(super) type CurrentSchedule<T: Config> = StorageValue<_, Schedule<T>, ValueQuery>; - // If poking the contract has lead to eviction of the contract, give out the rewards. - match Rent::<T, PrefabWasmModule<T>>::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::<T>::ContractNotEvictable.with_weight( - T::WeightInfo::claim_surcharge(code_len / 1024) - )), + /// A mapping from an original code hash to the original code, untouched by instrumentation. + #[pallet::storage] + pub type PristineCode<T: Config> = StorageMap<_, Identity, CodeHash<T>, Vec<u8>>; + + /// A mapping between an original code hash and instrumented wasm code, ready for execution. + #[pallet::storage] + pub type CodeStorage<T: Config> = StorageMap<_, Identity, CodeHash<T>, PrefabWasmModule<T>>; + + /// The subtrie counter. + #[pallet::storage] + pub type AccountCounter<T: Config> = StorageValue<_, u64, ValueQuery>; + + /// The code associated with a given account. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. + #[pallet::storage] + pub type ContractInfoOf<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, ContractInfo<T>>; + + /// 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<T: Config> = StorageValue<_, Vec<DeletedContract>, ValueQuery>; + + #[pallet::genesis_config] + pub struct GenesisConfig<T: Config> { + #[doc = "Current cost schedule for contracts."] + pub current_schedule: Schedule<T>, + } + + #[cfg(feature = "std")] + impl<T: Config> Default for GenesisConfig<T> { + fn default() -> Self { + Self { + current_schedule: Default::default(), } } } + + #[pallet::genesis_build] + impl<T: Config> GenesisBuild<T> for GenesisConfig<T> { + fn build(&self) { + <CurrentSchedule<T>>::put(&self.current_schedule); + } + } } impl<T: Config> Module<T> @@ -717,7 +671,7 @@ where origin: T::AccountId, dest: T::AccountId, value: BalanceOf<T>, - gas_limit: Gas, + gas_limit: Weight, input_data: Vec<u8>, ) -> ContractExecResult { let mut gas_meter = GasMeter::new(gas_limit); @@ -783,7 +737,7 @@ where /// Store code for benchmarks which does not check nor instrument the code. #[cfg(feature = "runtime-benchmarks")] - fn store_code_raw(code: Vec<u8>) -> DispatchResult { + fn store_code_raw(code: Vec<u8>) -> frame_support::dispatch::DispatchResult { let schedule = <Module<T>>::current_schedule(); PrefabWasmModule::store_code_unchecked(code, &schedule)?; Ok(()) @@ -794,99 +748,129 @@ where fn reinstrument_module( module: &mut PrefabWasmModule<T>, schedule: &Schedule<T> - ) -> DispatchResult { + ) -> frame_support::dispatch::DispatchResult { self::wasm::reinstrument(module, schedule) } } -decl_event! { - pub enum Event<T> - where - Balance = BalanceOf<T>, - <T as frame_system::Config>::AccountId, - <T as frame_system::Config>::Hash - { - /// Contract deployed by address at the specified address. \[deployer, contract\] - Instantiated(AccountId, AccountId), +/// 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<T: Config> { + Alive(AliveContractInfo<T>), + Tombstone(TombstoneContractInfo<T>), +} - /// Contract has been evicted and is now in tombstone state. \[contract\] - Evicted(AccountId), +impl<T: Config> ContractInfo<T> { + /// If contract is alive then return some alive info + pub fn get_alive(self) -> Option<AliveContractInfo<T>> { + 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<T>> { + 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<T>> { + if let ContractInfo::Alive(ref mut alive) = self { + Some(alive) + } else { + None + } + } - /// 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(AccountId, AccountId), + /// If contract is tombstone then return some tombstone info + pub fn get_tombstone(self) -> Option<TombstoneContractInfo<T>> { + 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<T>> { + 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<T>> { + if let ContractInfo::Tombstone(ref mut tombstone) = self { + Some(tombstone) + } else { + None + } + } +} - /// 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(AccountId, AccountId, Hash, Balance), +/// 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<CodeHash, Balance, BlockNumber> { + /// 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<BlockNumber>, +} - /// Code with the specified hash has been stored. \[code_hash\] - CodeStored(Hash), +impl<CodeHash, Balance, BlockNumber> RawAliveContractInfo<CodeHash, Balance, BlockNumber> { + /// 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[..]) + } +} - /// Triggered when the current schedule is updated. - /// \[version\] - /// - /// # Params - /// - /// - `version`: The version of the newly set schedule. - ScheduleUpdated(u32), +/// 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) +} - /// 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(AccountId, Vec<u8>), +#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug)] +pub struct RawTombstoneContractInfo<H, Hasher>(H, PhantomData<Hasher>); - /// 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(Hash), +impl<H, Hasher> RawTombstoneContractInfo<H, Hasher> +where + H: Member + MaybeSerializeDeserialize+ Debug + + AsRef<[u8]> + AsMut<[u8]> + Copy + Default + + sp_std::hash::Hash + Codec, + Hasher: Hash<Output=H>, +{ + 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(<Hasher as Hash>::hash(&buf[..]), PhantomData) } } -decl_storage! { - trait Store for Module<T: Config> as Contracts - where - T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]> - { - /// Current cost schedule for contracts. - CurrentSchedule get(fn current_schedule) config(): Schedule<T> = Default::default(); - /// A mapping from an original code hash to the original code, untouched by instrumentation. - pub PristineCode: map hasher(identity) CodeHash<T> => Option<Vec<u8>>; - /// A mapping between an original code hash and instrumented wasm code, ready for execution. - pub CodeStorage: map hasher(identity) CodeHash<T> => Option<PrefabWasmModule<T>>; - /// The subtrie counter. - pub AccountCounter: u64 = 0; - /// The code associated with a given account. - /// - /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. - pub ContractInfoOf: map hasher(twox_64_concat) T::AccountId => Option<ContractInfo<T>>; - /// 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`. - pub DeletionQueue: Vec<storage::DeletedContract>; +impl<T: Config> From<AliveContractInfo<T>> for ContractInfo<T> { + fn from(alive_info: AliveContractInfo<T>) -> Self { + Self::Alive(alive_info) } } diff --git a/substrate/frame/contracts/src/rent.rs b/substrate/frame/contracts/src/rent.rs index 087c6c518300ba368907685152a426b3ebbe98fe..85b8eff9893196e540138ae170a09286f37b7951 100644 --- a/substrate/frame/contracts/src/rent.rs +++ b/substrate/frame/contracts/src/rent.rs @@ -18,7 +18,7 @@ //! A module responsible for computing the right amount of weight and charging it. use crate::{ - AliveContractInfo, BalanceOf, ContractInfo, ContractInfoOf, Module, RawEvent, + AliveContractInfo, BalanceOf, ContractInfo, ContractInfoOf, Module, Event, TombstoneContractInfo, Config, CodeHash, Error, storage::Storage, wasm::PrefabWasmModule, exec::Executable, }; @@ -26,7 +26,7 @@ use sp_std::prelude::*; use sp_io::hashing::blake2_256; use sp_core::crypto::UncheckedFrom; use frame_support::{ - debug, StorageMap, + debug, storage::child, traits::{Currency, ExistenceRequirement, Get, OnUnbalanced, WithdrawReasons}, }; @@ -268,7 +268,7 @@ where let tombstone_info = ContractInfo::Tombstone(tombstone); <ContractInfoOf<T>>::insert(account, &tombstone_info); code.drop_from_storage(); - <Module<T>>::deposit_event(RawEvent::Evicted(account.clone())); + <Module<T>>::deposit_event(Event::Evicted(account.clone())); Ok(None) } (Verdict::Evict { amount: _ }, None) => { diff --git a/substrate/frame/contracts/src/storage.rs b/substrate/frame/contracts/src/storage.rs index 2a2d5da225d61b018695c255dbf840744cca46fb..244ab3788979a29d09101b8bb9c57ae2f78de543 100644 --- a/substrate/frame/contracts/src/storage.rs +++ b/substrate/frame/contracts/src/storage.rs @@ -31,9 +31,8 @@ use sp_runtime::traits::{Bounded, Saturating, Zero}; use sp_core::crypto::UncheckedFrom; use frame_support::{ dispatch::DispatchResult, - StorageMap, debug, - storage::{child::{self, KillOutcome}, StorageValue}, + storage::child::{self, KillOutcome}, traits::Get, weights::Weight, }; @@ -196,10 +195,10 @@ where /// You must make sure that the contract is also removed or converted into a tombstone /// when queuing the trie for deletion. pub fn queue_trie_for_deletion(contract: &AliveContractInfo<T>) -> DispatchResult { - if DeletionQueue::decode_len().unwrap_or(0) >= T::DeletionQueueDepth::get() as usize { + if <DeletionQueue<T>>::decode_len().unwrap_or(0) >= T::DeletionQueueDepth::get() as usize { Err(Error::<T>::DeletionQueueFull.into()) } else { - DeletionQueue::append(DeletedContract { + <DeletionQueue<T>>::append(DeletedContract { pair_count: contract.pair_count, trie_id: contract.trie_id.clone(), }); @@ -234,7 +233,7 @@ where /// It returns the amount of weight used for that task or `None` when no weight was used /// apart from the base weight. pub fn process_deletion_queue_batch(weight_limit: Weight) -> Weight { - let queue_len = DeletionQueue::decode_len().unwrap_or(0); + let queue_len = <DeletionQueue<T>>::decode_len().unwrap_or(0); if queue_len == 0 { return weight_limit; } @@ -251,7 +250,7 @@ where return weight_limit; } - let mut queue = DeletionQueue::get(); + let mut queue = <DeletionQueue<T>>::get(); while !queue.is_empty() && remaining_key_budget > 0 { // Cannot panic due to loop condition @@ -283,7 +282,7 @@ where .saturating_sub(remaining_key_budget.min(pair_count)); } - DeletionQueue::put(queue); + <DeletionQueue<T>>::put(queue); weight_limit.saturating_sub(weight_per_key.saturating_mul(remaining_key_budget as Weight)) } @@ -293,7 +292,7 @@ where use sp_runtime::traits::Hash; // Note that skipping a value due to error is not an issue here. // We only need uniqueness, not sequence. - let new_seed = AccountCounter::mutate(|v| { + let new_seed = <AccountCounter<T>>::mutate(|v| { *v = v.wrapping_add(1); *v }); @@ -322,6 +321,6 @@ where trie_id: vec![], }) .collect(); - DeletionQueue::put(queue); + <DeletionQueue<T>>::put(queue); } } diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index f10cd2882ace454066828b4ca4a3adae82f2ab1b..3fa806799e95c7e9babccae65ae6329b3025a8a5 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -17,14 +17,15 @@ use crate::{ BalanceOf, ContractInfo, ContractInfoOf, Module, - RawAliveContractInfo, RawEvent, Config, Schedule, gas::Gas, - Error, RuntimeReturnCode, storage::Storage, + RawAliveContractInfo, Config, Schedule, + Error, storage::Storage, chain_extension::{ Result as ExtensionResult, Environment, ChainExtension, Ext, SysConfig, RetVal, UncheckedFrom, InitState, ReturnFlags, }, exec::{AccountIdOf, Executable}, wasm::PrefabWasmModule, weights::WeightInfo, + wasm::ReturnCode as RuntimeReturnCode, }; use assert_matches::assert_matches; use codec::Encode; @@ -36,8 +37,8 @@ use sp_runtime::{ use sp_io::hashing::blake2_256; use frame_support::{ assert_ok, assert_err, assert_err_ignore_postinfo, - parameter_types, StorageMap, StorageValue, assert_storage_noop, - traits::{Currency, ReservableCurrency, OnInitialize}, + parameter_types, assert_storage_noop, + traits::{Currency, ReservableCurrency, OnInitialize, GenesisBuild}, weights::{Weight, PostDispatchInfo, DispatchClass, constants::WEIGHT_PER_SECOND}, dispatch::DispatchErrorWithPostInfo, storage::child, @@ -73,7 +74,7 @@ pub mod test_utils { exec::{StorageKey, AccountIdOf}, Module as Contracts, }; - use frame_support::{StorageMap, traits::Currency}; + use frame_support::traits::Currency; pub fn set_storage(addr: &AccountIdOf<Test>, key: &StorageKey, value: Option<Vec<u8>>) { let contract_info = <ContractInfoOf::<Test>>::get(&addr).unwrap().get_alive().unwrap(); @@ -292,7 +293,7 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); -const GAS_LIMIT: Gas = 10_000_000_000; +const GAS_LIMIT: Weight = 10_000_000_000; pub struct ExtBuilder { existential_deposit: u64, @@ -501,19 +502,19 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::CodeStored(code_hash.into())), + event: Event::pallet_contracts(crate::Event::CodeStored(code_hash.into())), topics: vec![], }, EventRecord { phase: Phase::Initialization, event: Event::pallet_contracts( - RawEvent::ContractEmitted(addr.clone(), vec![1, 2, 3, 4]) + crate::Event::ContractEmitted(addr.clone(), vec![1, 2, 3, 4]) ), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::Instantiated(ALICE, addr.clone())), + event: Event::pallet_contracts(crate::Event::Instantiated(ALICE, addr.clone())), topics: vec![], }, ]); @@ -1230,12 +1231,16 @@ fn restoration( }, EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::CodeStored(set_rent_code_hash.into())), + event: Event::pallet_contracts( + crate::Event::CodeStored(set_rent_code_hash.into()) + ), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::Instantiated(ALICE, addr_bob.clone())), + event: Event::pallet_contracts( + crate::Event::Instantiated(ALICE, addr_bob.clone()) + ), topics: vec![], }, ]; @@ -1275,7 +1280,9 @@ fn restoration( }, EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::Instantiated(ALICE, addr_dummy.clone())), + event: Event::pallet_contracts( + crate::Event::Instantiated(ALICE, addr_dummy.clone()) + ), topics: vec![], }, ].iter().cloned()); @@ -1401,7 +1408,7 @@ fn restoration( assert_eq!(System::events(), vec![ EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::Evicted(addr_bob)), + event: Event::pallet_contracts(crate::Event::Evicted(addr_bob)), topics: vec![], }, EventRecord { @@ -1433,12 +1440,16 @@ fn restoration( }, EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::CodeStored(restoration_code_hash)), + event: Event::pallet_contracts( + crate::Event::CodeStored(restoration_code_hash) + ), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::Instantiated(CHARLIE, addr_django.clone())), + event: Event::pallet_contracts( + crate::Event::Instantiated(CHARLIE, addr_django.clone()) + ), topics: vec![], }, @@ -1470,7 +1481,7 @@ fn restoration( assert_eq!(System::events(), vec![ EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::CodeRemoved(restoration_code_hash)), + event: Event::pallet_contracts(crate::Event::CodeRemoved(restoration_code_hash)), topics: vec![], }, EventRecord { @@ -1481,7 +1492,9 @@ fn restoration( EventRecord { phase: Phase::Initialization, event: Event::pallet_contracts( - RawEvent::Restored(addr_django, addr_bob, bob_contract.code_hash, 50) + crate::Event::Restored( + addr_django, addr_bob, bob_contract.code_hash, 50 + ) ), topics: vec![], }, @@ -1720,13 +1733,13 @@ fn self_destruct_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::pallet_contracts(RawEvent::CodeRemoved(code_hash)), + event: Event::pallet_contracts(crate::Event::CodeRemoved(code_hash)), topics: vec![], }, EventRecord { phase: Phase::Initialization, event: Event::pallet_contracts( - RawEvent::Terminated(addr.clone(), DJANGO) + crate::Event::Terminated(addr.clone(), DJANGO) ), topics: vec![], }, diff --git a/substrate/frame/contracts/src/wasm/code_cache.rs b/substrate/frame/contracts/src/wasm/code_cache.rs index 1132d31776db61f617deca13ca623775e3a71e78..0b2512f17f594b5da8cbd2088de0475a3deee7ad 100644 --- a/substrate/frame/contracts/src/wasm/code_cache.rs +++ b/substrate/frame/contracts/src/wasm/code_cache.rs @@ -28,13 +28,13 @@ //! Thus, before executing a contract it should be reinstrument with new schedule. use crate::{ - CodeHash, CodeStorage, PristineCode, Schedule, Config, Error, - wasm::{prepare, PrefabWasmModule}, Module as Contracts, RawEvent, - gas::{Gas, GasMeter, Token}, + CodeHash, CodeStorage, PristineCode, Schedule, Config, Error, Weight, + wasm::{prepare, PrefabWasmModule}, Module as Contracts, Event, + gas::{GasMeter, Token}, weights::WeightInfo, }; use sp_core::crypto::UncheckedFrom; -use frame_support::{StorageMap, dispatch::DispatchError}; +use frame_support::dispatch::DispatchError; #[cfg(feature = "runtime-benchmarks")] pub use self::private::reinstrument as reinstrument; @@ -58,7 +58,7 @@ where Some(module) => increment_64(&mut module.refcount), None => { *existing = Some(prefab_module); - Contracts::<T>::deposit_event(RawEvent::CodeStored(code_hash)) + Contracts::<T>::deposit_event(Event::CodeStored(code_hash)) } } }); @@ -170,7 +170,7 @@ where T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]> { <PristineCode<T>>::remove(code_hash); - Contracts::<T>::deposit_event(RawEvent::CodeRemoved(code_hash)) + Contracts::<T>::deposit_event(Event::CodeRemoved(code_hash)) } /// Increment the refcount panicking if it should ever overflow (which will not happen). @@ -196,7 +196,7 @@ struct InstrumentToken(u32); impl<T: Config> Token<T> for InstrumentToken { type Metadata = (); - fn calculate_amount(&self, _metadata: &Self::Metadata) -> Gas { + fn calculate_amount(&self, _metadata: &Self::Metadata) -> Weight { T::WeightInfo::instrument(self.0 / 1024) } } diff --git a/substrate/frame/contracts/src/wasm/env_def/macros.rs b/substrate/frame/contracts/src/wasm/env_def/macros.rs index dbb6705e9722d7d257ed034e944932b5dc240297..3c10d3225e43094b9bbb322eca52c5da7dd0e5e3 100644 --- a/substrate/frame/contracts/src/wasm/env_def/macros.rs +++ b/substrate/frame/contracts/src/wasm/env_def/macros.rs @@ -20,13 +20,11 @@ //! //! Most likely you should use `define_env` macro. -#[macro_export] macro_rules! convert_args { () => (vec![]); ( $( $t:ty ),* ) => ( vec![ $( { use $crate::wasm::env_def::ConvertibleToWasm; <$t>::VALUE_TYPE }, )* ] ); } -#[macro_export] macro_rules! gen_signature { ( ( $( $params: ty ),* ) ) => ( { @@ -43,7 +41,6 @@ macro_rules! gen_signature { ); } -#[macro_export] macro_rules! gen_signature_dispatch { ( $needle_name:ident, @@ -102,7 +99,6 @@ where f } -#[macro_export] macro_rules! unmarshall_then_body_then_marshall { ( $args_iter:ident, $ctx:ident, ( $( $names:ident : $params:ty ),* ) -> $returns:ty => $body:tt ) => ({ let body = $crate::wasm::env_def::macros::constrain_closure::< @@ -128,7 +124,6 @@ macro_rules! unmarshall_then_body_then_marshall { }) } -#[macro_export] macro_rules! define_func { ( < E: $seal_ty:tt > $name:ident ( $ctx: ident $(, $names:ident : $params:ty)*) $(-> $returns:ty)* => $body:tt ) => { fn $name< E: $seal_ty >( @@ -152,7 +147,6 @@ macro_rules! define_func { }; } -#[macro_export] macro_rules! register_func { ( $reg_cb:ident, < E: $seal_ty:tt > ; ) => {}; @@ -215,9 +209,9 @@ mod tests { use sp_runtime::traits::Zero; use sp_sandbox::{ReturnValue, Value}; use crate::{ + Weight, wasm::{Runtime, runtime::TrapReason, tests::MockExt}, exec::Ext, - gas::Gas, }; struct TestRuntime { @@ -282,7 +276,7 @@ mod tests { #[test] fn macro_define_func() { define_func!( <E: Ext> seal_gas (_ctx, amount: u32) => { - let amount = Gas::from(amount); + let amount = Weight::from(amount); if !amount.is_zero() { Ok(()) } else { @@ -334,7 +328,7 @@ mod tests { define_env!(Env, <E: Ext>, seal_gas( _ctx, amount: u32 ) => { - let amount = Gas::from(amount); + let amount = Weight::from(amount); if !amount.is_zero() { Ok(()) } else { diff --git a/substrate/frame/contracts/src/wasm/env_def/mod.rs b/substrate/frame/contracts/src/wasm/env_def/mod.rs index 0d9ceeee02373ec81c41eb501272741334566f36..997ec29e028d5df029243dcaa651c7c98477527e 100644 --- a/substrate/frame/contracts/src/wasm/env_def/mod.rs +++ b/substrate/frame/contracts/src/wasm/env_def/mod.rs @@ -22,7 +22,7 @@ use sp_sandbox::Value; use parity_wasm::elements::{FunctionType, ValueType}; #[macro_use] -pub(crate) mod macros; +pub mod macros; pub trait ConvertibleToWasm: Sized { const VALUE_TYPE: ValueType; @@ -67,13 +67,13 @@ impl ConvertibleToWasm for u64 { } } -pub(crate) type HostFunc<E> = +pub type HostFunc<E> = fn( &mut Runtime<E>, &[sp_sandbox::Value] ) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError>; -pub(crate) trait FunctionImplProvider<E: Ext> { +pub trait FunctionImplProvider<E: Ext> { fn impls<F: FnMut(&[u8], HostFunc<E>)>(f: &mut F); } diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index c6970b2b1eb060d239a067d096618a7a8f01288a..9001e2b8e92d713f873031572157c7cd043223e3 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -38,6 +38,8 @@ use pallet_contracts_primitives::ExecResult; pub use self::runtime::{ReturnCode, Runtime, RuntimeToken}; #[cfg(feature = "runtime-benchmarks")] pub use self::code_cache::reinstrument; +#[cfg(test)] +pub use tests::MockExt; /// A prepared wasm module ready for execution. /// @@ -237,7 +239,7 @@ mod tests { use crate::{ CodeHash, BalanceOf, Error, Module as Contracts, exec::{Ext, StorageKey, AccountIdOf, Executable}, - gas::{Gas, GasMeter}, + gas::GasMeter, tests::{Test, Call, ALICE, BOB}, }; use std::collections::HashMap; @@ -248,7 +250,7 @@ mod tests { use assert_matches::assert_matches; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags, ExecError, ErrorOrigin}; - const GAS_LIMIT: Gas = 10_000_000_000; + const GAS_LIMIT: Weight = 10_000_000_000; #[derive(Debug, PartialEq, Eq)] struct DispatchEntry(Call); @@ -1202,7 +1204,7 @@ mod tests { &mut gas_meter, ).unwrap(); - let gas_left = Gas::decode(&mut output.data.as_slice()).unwrap(); + let gas_left = Weight::decode(&mut output.data.as_slice()).unwrap(); assert!(gas_left < GAS_LIMIT, "gas_left must be less than initial"); assert!(gas_left > gas_meter.gas_left(), "gas_left must be greater than final"); } diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 020be381851f8131974e3b5538a4ee97593929e8..e0f7626b95a9fb5a3db780f442fe293869f4f558 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -20,11 +20,11 @@ use crate::{ HostFnWeights, Config, CodeHash, BalanceOf, Error, exec::{Ext, StorageKey, TopicOf}, - gas::{Gas, GasMeter, Token, ChargedAmount}, + gas::{GasMeter, Token, ChargedAmount}, wasm::env_def::ConvertibleToWasm, }; use parity_wasm::elements::ValueType; -use frame_support::{dispatch::DispatchError, ensure, traits::Get}; +use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight}; use sp_std::prelude::*; use codec::{Decode, DecodeAll, Encode}; use sp_runtime::traits::SaturatedConversion; @@ -223,7 +223,7 @@ where { type Metadata = HostFnWeights<T>; - fn calculate_amount(&self, s: &Self::Metadata) -> Gas { + fn calculate_amount(&self, s: &Self::Metadata) -> Weight { use self::RuntimeToken::*; match *self { MeteringBlock(amount) => s.gas.saturating_add(amount.into()),