Skip to content
runtime.rs 70.6 KiB
Newer Older
Sergey Pepyakin's avatar
Sergey Pepyakin committed
// This file is part of Substrate.

// Copyright (C) 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.
Sergey Pepyakin's avatar
Sergey Pepyakin committed

//! Environment definition of the wasm smart-contract runtime.

	exec::{ExecError, ExecResult, Ext, Key, TopicOf},
	gas::{ChargedAmount, Token},
	primitives::ExecReturnValue,
	BalanceOf, CodeHash, Config, DebugBufferVec, Error, SENTINEL,
use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
use frame_support::{
	dispatch::DispatchInfo,
	ensure,
	pallet_prelude::{DispatchResult, DispatchResultWithPostInfo},
	parameter_types,
	traits::Get,
	weights::Weight,
use pallet_contracts_proc_macro::define_env;
use pallet_contracts_uapi::{CallFlags, ReturnFlags};
use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256};
use sp_runtime::{
	traits::{Bounded, Zero},
	DispatchError, RuntimeDebug,
use sp_std::{fmt, prelude::*};
use wasmi::{core::HostError, errors::LinkerError, Linker, Memory, Store};
use xcm::VersionedXcm;

type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
/// The maximum nesting depth a contract can use when encoding types.
const MAX_DECODE_NESTING: u32 = 256;

/// Passed to [`Environment`] to determine whether it should expose deprecated interfaces.
pub enum AllowDeprecatedInterface {
	/// No deprecated interfaces are exposed.
	No,
	/// Deprecated interfaces are exposed.
	Yes,
}

/// Passed to [`Environment`] to determine whether it should expose unstable interfaces.
pub enum AllowUnstableInterface {
	/// No unstable interfaces are exposed.
	No,
	/// Unstable interfaces are exposed.
	Yes,
}

/// Trait implemented by the [`define_env`](pallet_contracts_proc_macro::define_env) macro for the
/// emitted `Env` struct.
pub trait Environment<HostState> {
	/// Adds all declared functions to the supplied [`Linker`](wasmi::Linker) and
	/// [`Store`](wasmi::Store).
	fn define(
		store: &mut Store<HostState>,
		linker: &mut Linker<HostState>,
		allow_unstable: AllowUnstableInterface,
		allow_deprecated: AllowDeprecatedInterface,
/// Type of a storage key.
enum KeyType {
	/// Legacy fix sized key `[u8;32]`.
	Fix,
	/// Variable sized key used in transparent hashing,
	/// cannot be larger than MaxStorageKeyLen.
pub use pallet_contracts_uapi::ReturnErrorCode;

parameter_types! {
	/// Getter types used by [`crate::api_doc::Current::call_runtime`]
	const CallRuntimeFailed: ReturnErrorCode = ReturnErrorCode::CallRuntimeFailed;
	/// Getter types used by [`crate::api_doc::Current::xcm_execute`]
	const XcmExecutionFailed: ReturnErrorCode = ReturnErrorCode::XcmExecutionFailed;
impl From<ExecReturnValue> for ReturnErrorCode {
	fn from(from: ExecReturnValue) -> Self {
		if from.flags.contains(ReturnFlags::REVERT) {
			Self::CalleeReverted
		} else {
			Self::Success
		}
	}
}
/// The data passed through when a contract uses `seal_return`.
	/// The flags as passed through by the contract. They are still unchecked and
	/// will later be parsed into a `ReturnFlags` bitflags struct.
	flags: u32,
	/// The output buffer passed by the contract as return data.
	data: Vec<u8>,
}

/// Enumerates all possible reasons why a trap was generated.
Sergey Pepyakin's avatar
Sergey Pepyakin committed
///
/// This is either used to supply the caller with more information about why an error
/// occurred (the SupervisorError variant).
/// The other case is where the trap does not constitute an error but rather was invoked
/// as a quick way to terminate the application (all other variants).
	/// The supervisor trapped the contract because of an error condition occurred during
	/// execution in privileged code.
	SupervisorError(DispatchError),
	/// Signals that trap was generated in response to call `seal_return` host function.
	Return(ReturnData),
	/// Signals that a trap was generated in response to a successful call to the
	Termination,
impl<T: Into<DispatchError>> From<T> for TrapReason {
	fn from(from: T) -> Self {
		Self::SupervisorError(from.into())
	}
}

impl fmt::Display for TrapReason {
	fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
		Ok(())
	}
}

impl HostError for TrapReason {}

#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
#[derive(Copy, Clone)]
pub enum RuntimeCosts {
	/// Weight charged for copying data from the sandbox.
	CopyFromContract(u32),
	/// Weight charged for copying data to the sandbox.
	CopyToContract(u32),
	/// Weight of calling `seal_caller`.
	Caller,
	/// Weight of calling `seal_is_contract`.
	IsContract,
	/// Weight of calling `seal_code_hash`.
	CodeHash,
	/// Weight of calling `seal_own_code_hash`.
	OwnCodeHash,
	/// Weight of calling `seal_caller_is_origin`.
	CallerIsOrigin,
	/// Weight of calling `caller_is_root`.
	CallerIsRoot,
	/// Weight of calling `seal_address`.
	Address,
	/// Weight of calling `seal_gas_left`.
	GasLeft,
	/// Weight of calling `seal_balance`.
	Balance,
	/// Weight of calling `seal_value_transferred`.
	ValueTransferred,
	/// Weight of calling `seal_minimum_balance`.
	MinimumBalance,
	/// Weight of calling `seal_block_number`.
	BlockNumber,
	/// Weight of calling `seal_now`.
	Now,
	/// Weight of calling `seal_weight_to_fee`.
	WeightToFee,
	/// Weight of calling `seal_input` without the weight of copying the input.
	InputBase,
	/// Weight of calling `seal_return` for the given output size.
	Return(u32),
	/// Weight of calling `seal_terminate`.
	Terminate,
	/// Weight of calling `seal_random`. It includes the weight for copying the subject.
	Random,
	/// Weight of calling `seal_deposit_event` with the given number of topics and event size.
	DepositEvent { num_topic: u32, len: u32 },
	/// Weight of calling `seal_debug_message` per byte of passed message.
	DebugMessage(u32),
	/// Weight of calling `seal_set_storage` for the given storage item sizes.
	SetStorage { old_bytes: u32, new_bytes: u32 },
	/// Weight of calling `seal_clear_storage` per cleared byte.
	ClearStorage(u32),
Loading full blame...