// 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 . //! # Contract Module //! //! The Contract module provides functionality for the runtime to deploy and execute WebAssembly smart-contracts. //! To use it in your runtime, you need to implement the [`contracts::Trait`](./trait.Trait.html). //! //! ## 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 create 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, create 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 //! //! * `put_code` - Stores the given binary Wasm code into the chain's storage and returns its `code_hash`. //! * `create` - Deploys a new contract from the given `code_hash`, optionally transferring some balance. //! This creates a new smart contract account and calls its contract deploy handler to initialize the contract. //! * `call` - Makes a call to an account, optionally transferring some balance. //! //! See the [`Call`](./enum.Call.html) enum and its associated variants for details of each function. //! //! ### Public functions //! //! See the [`Module`](./struct.Module.html) struct for details on publicly available functions. //! //! ## Usage //! //! The Contract module is a work in progress. The following examples show how this Contract module can be //! used to create and call contracts. //! //! * [`pDSL`](https://github.com/Robbepop/pdsl) is a domain specific language that enables writing //! WebAssembly based smart contracts in the Rust programming language. This is a work in progress. //! //! ## Related Modules //! //! * [`Balances`](../srml_balances/index.html) #![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 substrate_primitives::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX; 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 account 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 storage_size: 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 be collision resistant /// (being a proper unique identifier). 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 calls 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 uses inner counter for account id and applies the 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()[..]); CHILD_STORAGE_KEY_PREFIX.iter() .chain(T::Hashing::hash(&buf[..]).as_ref().iter()) .cloned() .collect() } } 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 the 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 determiner. /// /// Address calculated from the code (of the constructor), input data to the constructor, /// and the account id that 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 /// the implementation of `MakePayment` for the 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 the given binary Wasm code into the chain's storage and returns its `codehash`. /// 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(|_| ()) } /// 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. 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(|_| ()) } /// Creates a new contract from the `codehash` generated by `put_code`, optionally transferring some balance. /// /// Creation is executed as follows: /// /// - The destination address is computed based on the sender and hash of the code. /// - The smart-contract 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 call received by this account. /// - The contract is initialized. fn create( origin, #[compact] endowment: BalanceOf, #[compact] gas_limit: T::Gas, code_hash: CodeHash, data: Vec ) -> Result { let origin = ensure_signed(origin)?; // Commit 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_finalize() { >::kill(); } } } decl_event! { pub enum Event where Balance = BalanceOf, ::AccountId, ::Hash { /// Transfer happened `from` to `to` with given `value` as part of a `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), /// An event from contract of account. Contract(AccountId, Vec), } } 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 instance. ContractFee get(contract_fee) config(): BalanceOf = BalanceOf::::sa(21); /// The base fee charged for calling into a contract. CallBaseFee get(call_base_fee) config(): T::Gas = T::Gas::sa(135); /// The base fee charged for creating 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 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(who).map(|info| child::kill_storage(&info.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 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 to deposit an event; the per-byte portion. pub event_data_per_byte_cost: Gas, /// Gas cost to deposit an event; the base. pub event_data_base_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, /// Maximum allowed stack height. /// /// See https://wiki.parity.io/WebAssembly-StackHeight to find out /// how the stack frame cost is calculated. pub max_stack_height: u32, /// Maximum number of memory pages allowed for a contract. pub max_memory_pages: u32, /// Whether the `ext_println` function is allowed to be used contracts. /// MUST only be enabled for `dev` chains, NOT for production chains pub enable_println: bool, } 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), event_data_per_byte_cost: Gas::sa(1), event_data_base_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, enable_println: false, } } }