Skip to content
lib.rs 42.5 KiB
Newer Older
// This file is part of Substrate.

// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd.
Bastian Köcher's avatar
Bastian Köcher committed
// SPDX-License-Identifier: Apache-2.0
Bastian Köcher's avatar
Bastian Köcher committed
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! The Contract module provides functionality for the runtime to deploy and execute WebAssembly
//! smart-contracts.
thiolliere's avatar
thiolliere committed
//! - [`Config`]
//! - [`Call`]
//! ## Overview
//! This module extends accounts based on the [`Currency`] trait to have smart-contract
//! functionality. It can be used with other modules that implement accounts based on [`Currency`].
//! These "smart-contract accounts" have the ability to instantiate smart-contracts and make calls
//! to other contract and non-contract accounts.
//! The smart-contract code is stored once in a code cache, and later retrievable via its hash.
//! This means that multiple smart-contracts can be instantiated from the same hash, without
//! replicating the code each time.
//! When a smart-contract is called, its associated code is retrieved via the code hash and gets
//! executed. This call can alter the storage entries of the smart-contract account, instantiate new
//! smart-contracts, or call other smart-contracts.
//! Finally, when an account is reaped, its associated code and storage of the smart-contract
//! account will also be deleted.
//! ### Gas
//! Senders must specify a gas limit with every call, as all instructions invoked by the
//! smart-contract require gas. Unused gas is refunded after the call, regardless of the execution
//! outcome.
//! If the gas limit is reached, then all calls and state changes (including balance transfers) are
//! only reverted at the current call's contract level. For example, if contract A calls B and B
//! runs out of gas mid-call, then all of B's calls are reverted. Assuming correct error handling by
//! contract A, A's other calls and state changes still persist.
//! ### Notable Scenarios
//! Contract call failures are not always cascading. When failures occur in a sub-call, they do not
//! "bubble up", and the call will only revert at the specific contract level. For example, if
//! contract A calls contract B, and B fails, A can decide how to handle that failure, either
//! proceeding or reverting A's changes.
//! ## Interface
//! ### Dispatchable functions
//! * [`Pallet::instantiate_with_code`] - Deploys a new contract from the supplied wasm binary,
//! optionally transferring
//! some balance. This instantiates a new smart contract account with the supplied code and
//! calls its constructor to initialize the contract.
//! * [`Pallet::instantiate`] - The same as `instantiate_with_code` but instead of uploading new
//! code an existing `code_hash` is supplied.
//! * [`Pallet::call`] - Makes a call to an account, optionally transferring some balance.
//! ## Usage
//! The Contract module is a work in progress. The following examples show how this Contract module
//! can be used to instantiate and call contracts.
//! * [`ink`](https://github.com/paritytech/ink) is
//! an [`eDSL`](https://wiki.haskell.org/Embedded_domain_specific_language) that enables writing
//! WebAssembly based smart contracts in the Rust programming language. This is a work in progress.
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "512")]
#[macro_use]
mod gas;
mod benchmarking;
mod storage;
mod wasm;
#[cfg(test)]
mod tests;
	exec::{AccountIdOf, ExecError, Executable, Stack as ExecStack},
	storage::{meter::Meter as StorageMeter, ContractInfo, DeletedContract, Storage},
	wasm::{OwnerInfo, PrefabWasmModule},
	weights::WeightInfo,
use codec::{Encode, HasCompact};
use frame_support::{
	dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo},
	traits::{
		tokens::fungible::Inspect, ConstU32, Contains, Currency, Get, Randomness,
		ReservableCurrency, Time,
	},
	weights::{OldWeight, Weight},
use frame_system::Pallet as System;
	Code, CodeUploadResult, CodeUploadReturnValue, ContractAccessError, ContractExecResult,
	ContractInstantiateResult, ExecReturnValue, GetStorageResult, InstantiateReturnValue,
	StorageDeposit,
use scale_info::TypeInfo;
use sp_core::crypto::UncheckedFrom;
use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup};
use sp_std::{fmt::Debug, marker::PhantomData, prelude::*};
pub use crate::{
	exec::{Frame, VarSizedKey as StorageKey},
	pallet::*,
	schedule::{HostFnWeights, InstructionWeights, Limits, Schedule},
};

type CodeHash<T> = <T as frame_system::Config>::Hash;
type TrieId = BoundedVec<u8, ConstU32<128>>;
type BalanceOf<T> =
	<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
type CodeVec<T> = BoundedVec<u8, <T as Config>::MaxCodeLen>;
type RelaxedCodeVec<T> = WeakBoundedVec<u8, <T as Config>::MaxCodeLen>;
type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
/// Used as a sentinel value when reading and writing contract memory.
///
/// It is usually used to signal `None` to a contract when only a primitive is allowed
/// and we don't want to go through encoding a full Rust type. Using `u32::Max` is a safe
/// sentinel because contracts are never allowed to use such a large amount of resources
/// that this value makes sense for a memory location or length.
const SENTINEL: u32 = u32::MAX;

/// Provides the contract address generation method.
///
/// See [`DefaultAddressGenerator`] for the default implementation.
pub trait AddressGenerator<T: frame_system::Config> {
	/// Generate the address of a contract based on the given instantiate parameters.
	///
	/// # Note for implementors
	/// 1. Make sure that there are no collisions, different inputs never lead to the same output.
	/// 2. Make sure that the same inputs lead to the same output.
	/// 3. Changing the implementation through a runtime upgrade without a proper storage migration
	/// would lead to catastrophic misbehavior.
	fn generate_address(
		deploying_address: &T::AccountId,
		code_hash: &CodeHash<T>,
		salt: &[u8],
	) -> T::AccountId;
}

/// Default address generator.
///
/// This is the default address generator used by contract instantiation. Its result
Sacha Lansky's avatar
Sacha Lansky committed
/// is only dependant on its inputs. It can therefore be used to reliably predict the
/// address of a contract. This is akin to the formula of eth's CREATE2 opcode. There
/// is no CREATE equivalent because CREATE2 is strictly more powerful.
///
/// Formula: `hash(deploying_address ++ code_hash ++ salt)`
pub struct DefaultAddressGenerator;

impl<T> AddressGenerator<T> for DefaultAddressGenerator
where
	T: frame_system::Config,
	T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
{
	fn generate_address(
		deploying_address: &T::AccountId,
		code_hash: &CodeHash<T>,
		salt: &[u8],
	) -> T::AccountId {
		let buf: Vec<_> = deploying_address
			.as_ref()
			.iter()
			.chain(code_hash.as_ref())
			.chain(salt)
			.cloned()
			.collect();
		UncheckedFrom::unchecked_from(T::Hashing::hash(&buf))
	}
}
Loading full blame...