Skip to content
runtime.rs 84.1 KiB
Newer Older
Sergey Pepyakin's avatar
Sergey Pepyakin committed
// 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.
Sergey Pepyakin's avatar
Sergey Pepyakin committed

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

	exec::{ExecError, ExecResult, Ext, FixSizedKey, TopicOf, VarSizedKey},
	gas::{ChargedAmount, Token},
	schedule::HostFnWeights,
	wasm::env_def::ConvertibleToWasm,
	BalanceOf, CodeHash, Config, Error, SENTINEL,
use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight};
use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags};
use pallet_contracts_proc_macro::define_env;
use sp_core::crypto::UncheckedFrom;
use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256};
use sp_runtime::traits::{Bounded, Zero};
use sp_std::prelude::*;
use wasm_instrument::parity_wasm::elements::ValueType;
/// The maximum nesting depth a contract can use when encoding types.
const MAX_DECODE_NESTING: u32 = 256;

/// Type of a storage key.
#[allow(dead_code)]
enum KeyType {
	/// Deprecated fix sized key [0;32].
	Fix,
	/// Variable sized key used in transparent hashing,
	/// cannot be larger than MaxStorageKeyLen.
	Variable(u32),
}

impl KeyType {
	fn len<T: Config>(&self) -> Result<u32, TrapReason> {
		match self {
			KeyType::Fix => Ok(32u32),
			KeyType::Variable(len) => {
				ensure!(len <= &<T>::MaxStorageKeyLen::get(), Error::<T>::DecodingFailed);
				Ok(*len)
			},
		}
	}
}

/// Every error that can be returned to a contract when it calls any of the host functions.
///
/// # Note
///
/// This enum can be extended in the future: New codes can be added but existing codes
/// will not be changed or removed. This means that any contract **must not** exhaustively
/// match return codes. Instead, contracts should prepare for unknown variants and deal with
/// those errors gracefully in order to be forward compatible.
#[repr(u32)]
pub enum ReturnCode {
	/// API call successful.
	Success = 0,
	/// The called function trapped and has its state changes reverted.
	/// In this case no output buffer is returned.
	CalleeTrapped = 1,
	/// The called function ran to completion but decided to revert its state.
	/// An output buffer is returned when one was supplied.
	CalleeReverted = 2,
	/// The passed key does not exist in storage.
	KeyNotFound = 3,
	/// Deprecated and no longer returned: There is only the minimum balance.
	_BelowSubsistenceThreshold = 4,
	/// See [`Error::TransferFailed`].
	TransferFailed = 5,
	/// Deprecated and no longer returned: Endowment is no longer required.
	_EndowmentTooLow = 6,
	/// No code could be found at the supplied code hash.
	CodeNotFound = 7,
	/// The contract that was called is no contract (a plain account).
	/// The call to `seal_debug_message` had no effect because debug message
	/// recording was disabled.
	LoggingDisabled = 9,
	/// The call dispatched by `seal_call_runtime` was executed but returned an error.
	#[cfg(feature = "unstable-interface")]
	CallRuntimeReturnedError = 10,
	/// ECDSA pubkey recovery failed (most probably wrong recovery id or signature), or
	/// ECDSA compressed pubkey conversion into Ethereum address failed (most probably
	/// wrong pubkey provided).
}

impl ConvertibleToWasm for ReturnCode {
	const VALUE_TYPE: ValueType = ValueType::I32;
	fn to_typed_value(self) -> sp_sandbox::Value {
		sp_sandbox::Value::I32(self as i32)
	}
	fn from_typed_value(_: sp_sandbox::Value) -> Option<Self> {
		debug_assert!(false, "We will never receive a ReturnCode but only send it to wasm.");
		None
	}
}

impl From<ExecReturnValue> for ReturnCode {
	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())
	}
}

#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
#[derive(Copy, Clone)]
pub enum RuntimeCosts {
	/// Charge the gas meter with the cost of a metering block. The charged costs are
	/// the supplied cost of the block plus the overhead of the metering itself.
	MeteringBlock(u64),
	/// 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 `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.
Loading full blame...