// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . //! Smart-contract module for runtime; Allows deployment and execution of smart-contracts //! expressed in WebAssembly. //! //! This module provides an ability to create smart-contract accounts and send them messages. //! A smart-contract is an account with associated code and storage. When such an account receives a message, //! the code associated with that account gets executed. //! //! The code is allowed to alter the storage entries of the associated account, //! create smart-contracts or send messages to existing smart-contracts. //! //! For any actions invoked by the smart-contracts fee must be paid. The fee is paid in gas. //! Gas is bought upfront up to the, specified in transaction, limit. Any unused gas is refunded //! after the transaction (regardless of the execution outcome). If all gas is used, //! then changes made for the specific call or create are reverted (including balance transfers). //! //! Failures are typically not cascading. That, for example, means that if contract A calls B and B errors //! somehow, then A can decide if it should proceed or error. //! //! # Interaction with the system //! //! ## Finalization //! //! This module requires performing some finalization steps at the end of the block. If not performed //! the module will have incorrect behavior. //! //! Thus [`Module::on_finalise`] must be called at the end of the block. The order in relation to //! the other module doesn't matter. //! //! ## Account killing //! //! When `staking` module determines that account is dead (e.g. account's balance fell below //! exsistential deposit) then it reaps the account. That will lead to deletion of the associated //! code and storage of the account. //! //! [`Module::on_finalise`]: struct.Module.html#impl-OnFinalise #![cfg_attr(not(feature = "std"), no_std)] #[macro_use] mod gas; mod account_db; mod exec; mod wasm; #[cfg(test)] mod tests; use crate::exec::ExecutionContext; use crate::account_db::{AccountDb, DirectAccountDb}; #[cfg(feature = "std")] use serde_derive::{Serialize, Deserialize}; use substrate_primitives::crypto::UncheckedFrom; use rstd::prelude::*; use rstd::marker::PhantomData; use parity_codec::{Codec, Encode, Decode}; use runtime_primitives::traits::{Hash, As, SimpleArithmetic,Bounded, StaticLookup}; use srml_support::dispatch::{Result, Dispatchable}; use srml_support::{Parameter, StorageMap, StorageValue, decl_module, decl_event, decl_storage, storage::child}; use srml_support::traits::{OnFreeBalanceZero, OnUnbalanced, Currency}; use system::{ensure_signed, RawOrigin}; use timestamp; pub type CodeHash = ::Hash; pub type TrieId = Vec; /// A function that generates an `AccountId` for a contract upon instantiation. pub trait ContractAddressFor { fn contract_address_for(code_hash: &CodeHash, data: &[u8], origin: &AccountId) -> AccountId; } /// A function that returns the fee for dispatching a `Call`. pub trait ComputeDispatchFee { fn compute_dispatch_fee(call: &Call) -> Balance; } #[derive(Encode,Decode,Clone,Debug)] /// Information for managing an acocunt and its sub trie abstraction. /// This is the required info to cache for an account pub struct AccountInfo { /// unique ID for the subtree encoded as a byte pub trie_id: TrieId, /// the size of stored value in octet pub current_mem_stored: u64, } /// Get a trie id (trie id must be unique and collision resistant depending upon its context) /// Note that it is different than encode because trie id should have collision resistance /// property (being a proper uniqueid). pub trait TrieIdGenerator { /// get a trie id for an account, using reference to parent account trie id to ensure /// uniqueness of trie id /// The implementation must ensure every new trie id is unique: two consecutive call with the /// same parameter needs to return different trie id values. fn trie_id(account_id: &AccountId) -> TrieId; } /// Get trie id from `account_id` pub struct TrieIdFromParentCounter(PhantomData); /// This generator use inner counter for account id and apply hash over `AccountId + /// accountid_counter` impl TrieIdGenerator for TrieIdFromParentCounter where T::AccountId: AsRef<[u8]> { fn trie_id(account_id: &T::AccountId) -> TrieId { // note that skipping a value due to error is not an issue here. // we only need uniqueness, not sequence. let new_seed = >::mutate(|v| v.wrapping_add(1)); let mut buf = Vec::new(); buf.extend_from_slice(account_id.as_ref()); buf.extend_from_slice(&new_seed.to_le_bytes()[..]); T::Hashing::hash(&buf[..]).as_ref().into() } } pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; pub type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; pub trait Trait: timestamp::Trait { type Currency: Currency; /// The outer call dispatch type. type Call: Parameter + Dispatchable::Origin>; /// The overarching event type. type Event: From> + Into<::Event>; // As is needed for wasm-utils type Gas: Parameter + Default + Codec + SimpleArithmetic + Bounded + Copy + As> + As + As; /// A function type to get the contract address given the creator. type DetermineContractAddress: ContractAddressFor, Self::AccountId>; /// A function type that computes the fee for dispatching the given `Call`. /// /// It is recommended (though not required) for this function to return a fee that would be taken /// by executive module for regular dispatch. type ComputeDispatchFee: ComputeDispatchFee>; /// trieid id generator type TrieIdGenerator: TrieIdGenerator; /// Handler for the unbalanced reduction when making a gas payment. type GasPayment: OnUnbalanced>; } /// Simple contract address determintator. /// /// Address calculated from the code (of the constructor), input data to the constructor /// and account id which requested the account creation. /// /// Formula: `blake2_256(blake2_256(code) + blake2_256(data) + origin)` pub struct SimpleAddressDeterminator(PhantomData); impl ContractAddressFor, T::AccountId> for SimpleAddressDeterminator where T::AccountId: UncheckedFrom + AsRef<[u8]> { fn contract_address_for(code_hash: &CodeHash, data: &[u8], origin: &T::AccountId) -> T::AccountId { let data_hash = T::Hashing::hash(data); let mut buf = Vec::new(); buf.extend_from_slice(code_hash.as_ref()); buf.extend_from_slice(data_hash.as_ref()); buf.extend_from_slice(origin.as_ref()); UncheckedFrom::unchecked_from(T::Hashing::hash(&buf[..])) } } /// The default dispatch fee computor computes the fee in the same way that /// implementation of `MakePayment` for balances module does. pub struct DefaultDispatchFeeComputor(PhantomData); impl ComputeDispatchFee> for DefaultDispatchFeeComputor { fn compute_dispatch_fee(call: &T::Call) -> BalanceOf { let encoded_len = call.using_encoded(|encoded| encoded.len()); let base_fee = >::transaction_base_fee(); let byte_fee = >::transaction_byte_fee(); base_fee + byte_fee * as As>::sa(encoded_len as u64) } } decl_module! { /// Contracts module. pub struct Module for enum Call where origin: ::Origin { fn deposit_event() = default; /// Updates the schedule for metering contracts. /// /// The schedule must have a greater version than the stored schedule. fn update_schedule(schedule: Schedule) -> Result { if >::current_schedule().version >= schedule.version { return Err("new schedule must have a greater version than current"); } Self::deposit_event(RawEvent::ScheduleUpdated(schedule.version)); >::put(schedule); Ok(()) } /// Stores code in the storage. You can instantiate contracts only with stored code. fn put_code( origin, #[compact] gas_limit: T::Gas, code: Vec ) -> Result { let origin = ensure_signed(origin)?; let schedule = >::current_schedule(); let (mut gas_meter, imbalance) = gas::buy_gas::(&origin, gas_limit)?; let result = wasm::save_code::(code, &mut gas_meter, &schedule); if let Ok(code_hash) = result { Self::deposit_event(RawEvent::CodeStored(code_hash)); } gas::refund_unused_gas::(&origin, gas_meter, imbalance); result.map(|_| ()) } /// Make a call to a specified account, optionally transferring some balance. fn call( origin, dest: ::Source, #[compact] value: BalanceOf, #[compact] gas_limit: T::Gas, data: Vec ) -> Result { let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; // Pay for the gas upfront. // // NOTE: it is very important to avoid any state changes before // paying for the gas. let (mut gas_meter, imbalance) = gas::buy_gas::(&origin, gas_limit)?; let cfg = Config::preload(); let vm = crate::wasm::WasmVm::new(&cfg.schedule); let loader = crate::wasm::WasmLoader::new(&cfg.schedule); let mut ctx = ExecutionContext::top_level(origin.clone(), &cfg, &vm, &loader); let result = ctx.call(dest, value, &mut gas_meter, &data, exec::EmptyOutputBuf::new()); if let Ok(_) = result { // Commit all changes that made it thus far into the persistant storage. DirectAccountDb.commit(ctx.overlay.into_change_set()); // Then deposit all events produced. ctx.events.into_iter().for_each(Self::deposit_event); } // Refund cost of the unused gas. // // NOTE: this should go after the commit to the storage, since the storage changes // can alter the balance of the caller. gas::refund_unused_gas::(&origin, gas_meter, imbalance); // Dispatch every recorded call with an appropriate origin. ctx.calls.into_iter().for_each(|(who, call)| { let result = call.dispatch(RawOrigin::Signed(who.clone()).into()); Self::deposit_event(RawEvent::Dispatched(who, result.is_ok())); }); result.map(|_| ()) } /// Create a new contract, optionally transferring some balance to the created account. /// /// Creation is executed as follows: /// /// - the destination address is computed based on the sender and hash of the code. /// - account is created at the computed address. /// - the `ctor_code` is executed in the context of the newly created account. Buffer returned /// after the execution is saved as the `code` of the account. That code will be invoked /// upon any message received by this account. fn create( origin, #[compact] endowment: BalanceOf, #[compact] gas_limit: T::Gas, code_hash: CodeHash, data: Vec ) -> Result { let origin = ensure_signed(origin)?; // Pay for the gas upfront. // // NOTE: it is very important to avoid any state changes before // paying for the gas. let (mut gas_meter, imbalance) = gas::buy_gas::(&origin, gas_limit)?; let cfg = Config::preload(); let vm = crate::wasm::WasmVm::new(&cfg.schedule); let loader = crate::wasm::WasmLoader::new(&cfg.schedule); let mut ctx = ExecutionContext::top_level(origin.clone(), &cfg, &vm, &loader); let result = ctx.instantiate(endowment, &mut gas_meter, &code_hash, &data); if let Ok(_) = result { // Commit all changes that made it thus far into the persistant storage. DirectAccountDb.commit(ctx.overlay.into_change_set()); // Then deposit all events produced. ctx.events.into_iter().for_each(Self::deposit_event); } // Refund cost of the unused gas. // // NOTE: this should go after the commit to the storage, since the storage changes // can alter the balance of the caller. gas::refund_unused_gas::(&origin, gas_meter, imbalance); // Dispatch every recorded call with an appropriate origin. ctx.calls.into_iter().for_each(|(who, call)| { let result = call.dispatch(RawOrigin::Signed(who.clone()).into()); Self::deposit_event(RawEvent::Dispatched(who, result.is_ok())); }); result.map(|_| ()) } fn on_finalise() { >::kill(); } } } decl_event! { pub enum Event where Balance = BalanceOf, ::AccountId, ::Hash { /// Transfer happened `from` -> `to` with given `value` as part of a `message-call` or `create`. Transfer(AccountId, AccountId, Balance), /// Contract deployed by address at the specified address. Instantiated(AccountId, AccountId), /// Code with the specified hash has been stored. CodeStored(Hash), /// Triggered when the current schedule is updated. ScheduleUpdated(u32), /// A call was dispatched from the given account. The bool signals whether it was /// successful execution or not. Dispatched(AccountId, bool), } } decl_storage! { trait Store for Module as Contract { /// The fee required to make a transfer. TransferFee get(transfer_fee) config(): BalanceOf; /// The fee required to create an account. CreationFee get(creation_fee) config(): BalanceOf; /// The fee to be paid for making a transaction; the base. TransactionBaseFee get(transaction_base_fee) config(): BalanceOf; /// The fee to be paid for making a transaction; the per-byte portion. TransactionByteFee get(transaction_byte_fee) config(): BalanceOf; /// The fee required to create a contract. ContractFee get(contract_fee) config(): BalanceOf = BalanceOf::::sa(21); /// The fee charged for a call into a contract. CallBaseFee get(call_base_fee) config(): T::Gas = T::Gas::sa(135); /// The fee charged for a create of a contract. CreateBaseFee get(create_base_fee) config(): T::Gas = T::Gas::sa(175); /// The price of one unit of gas. GasPrice get(gas_price) config(): BalanceOf = BalanceOf::::sa(1); /// The maximum nesting level of a call/create stack. MaxDepth get(max_depth) config(): u32 = 100; /// The maximum amount of gas that could be expended per block. BlockGasLimit get(block_gas_limit) config(): T::Gas = T::Gas::sa(1_000_000); /// Gas spent so far in this block. GasSpent get(gas_spent): T::Gas; /// Current cost schedule for contracts. CurrentSchedule get(current_schedule) config(): Schedule = Schedule::default(); /// The code associated with a given account. pub CodeHashOf: map T::AccountId => Option>; /// A mapping from an original code hash to the original code, untouched by instrumentation. pub PristineCode: map CodeHash => Option>; /// A mapping between an original code hash and instrumented wasm code, ready for the execution. pub CodeStorage: map CodeHash => Option; /// The subtrie counter pub AccountCounter: u64 = 0; /// The code associated with a given account. pub AccountInfoOf: map T::AccountId => Option; } } impl OnFreeBalanceZero for Module { fn on_free_balance_zero(who: &T::AccountId) { >::remove(who); >::get_account_info(&DirectAccountDb, who).map(|subtrie| { child::kill_storage(&subtrie.trie_id); }); } } /// In-memory cache of configuration values. /// /// We assume that these values can't be changed in the /// course of transaction execution. pub struct Config { pub schedule: Schedule, pub existential_deposit: BalanceOf, pub max_depth: u32, pub contract_account_instantiate_fee: BalanceOf, pub account_create_fee: BalanceOf, pub transfer_fee: BalanceOf, pub call_base_fee: T::Gas, pub instantiate_base_fee: T::Gas, } impl Config { fn preload() -> Config { Config { schedule: >::current_schedule(), existential_deposit: T::Currency::minimum_balance(), max_depth: >::max_depth(), contract_account_instantiate_fee: >::contract_fee(), account_create_fee: >::creation_fee(), transfer_fee: >::transfer_fee(), call_base_fee: >::call_base_fee(), instantiate_base_fee: >::create_base_fee(), } } } /// Definition of the cost schedule and other parameterizations for wasm vm. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[derive(Clone, Encode, Decode, PartialEq, Eq)] pub struct Schedule { /// Version of the schedule. pub version: u32, /// Cost of putting a byte of code into the storage. pub put_code_per_byte_cost: Gas, /// Gas cost of a growing memory by single page. pub grow_mem_cost: Gas, /// Gas cost of a regular operation. pub regular_op_cost: Gas, /// Gas cost per one byte returned. pub return_data_per_byte_cost: Gas, /// Gas cost per one byte read from the sandbox memory. pub sandbox_data_read_cost: Gas, /// Gas cost per one byte written to the sandbox memory. pub sandbox_data_write_cost: Gas, /// How tall the stack is allowed to grow? /// /// See https://wiki.parity.io/WebAssembly-StackHeight to find out /// how the stack frame cost is calculated. pub max_stack_height: u32, /// What is the maximal memory pages amount is allowed to have for /// a contract. pub max_memory_pages: u32, } impl> Default for Schedule { fn default() -> Schedule { Schedule { version: 0, put_code_per_byte_cost: Gas::sa(1), grow_mem_cost: Gas::sa(1), regular_op_cost: Gas::sa(1), return_data_per_byte_cost: Gas::sa(1), sandbox_data_read_cost: Gas::sa(1), sandbox_data_write_cost: Gas::sa(1), max_stack_height: 64 * 1024, max_memory_pages: 16, } } }