Newer
Older
// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// 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.
//! Environment definition of the wasm smart-contract runtime.
Alexander Theißen
committed
use crate::{
exec::{ExecError, ExecResult, Ext, StorageKey, TopicOf},
gas::{ChargedAmount, Token},
wasm::env_def::ConvertibleToWasm,
BalanceOf, CodeHash, Config, Error,
use bitflags::bitflags;
Igor Matuszewski
committed
use codec::{Decode, DecodeAll, Encode, MaxEncodedLen};
use frame_support::{dispatch::DispatchError, ensure, weights::Weight};
use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags};
use pwasm_utils::parity_wasm::elements::ValueType;
use sp_core::{crypto::UncheckedFrom, Bytes};
use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256};
use sp_runtime::traits::Bounded;
/// 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 gracefuly 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,
/// Transfer failed because it would have brought the sender's total balance below the
/// subsistence threshold.
BelowSubsistenceThreshold = 4,
/// Transfer failed for other reasons. Most probably reserved or locked balance of the
/// sender prevents the transfer.
TransferFailed = 5,
/// The newly created contract is below the subsistence threshold after executing
/// its constructor.
NewContractNotFunded = 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.
#[cfg(feature = "unstable-interface")]
EcdsaRecoverFailed = 11,
}
impl ConvertibleToWasm for ReturnCode {
type NativeType = Self;
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
}
}
}
Alexander Theißen
committed
/// The data passed through when a contract uses `seal_return`.
Alexander Theißen
committed
pub struct ReturnData {
/// 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.
/// 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).
Alexander Theißen
committed
pub enum TrapReason {
/// The supervisor trapped the contract because of an error condition occurred during
/// execution in privileged code.
SupervisorError(DispatchError),
Alexander Theißen
committed
/// Signals that trap was generated in response to call `seal_return` host function.
/// Signals that a trap was generated in response to a successful call to the
Alexander Theißen
committed
/// `seal_terminate` host function.
Alexander Theißen
committed
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)]
/// 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(u32),
/// Weight of calling `seal_caller`.
Caller,
/// 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_contract_deposit`.
ContractDeposit,
/// 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 copying the input data for the given size.
InputCopyOut(u32),
/// 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`.
DebugMessage,
/// Weight of calling `seal_set_storage` for the given storage item size.
SetStorage(u32),
/// Weight of calling `seal_clear_storage`.
ClearStorage,
/// Weight of calling `seal_get_storage` without output weight.
GetStorageBase,
/// Weight of an item received via `seal_get_storage` for the given size.
GetStorageCopyOut(u32),
/// Weight of calling `seal_transfer`.
Transfer,
/// Weight of calling `seal_call` for the given input size.
CallBase(u32),
/// Weight of the transfer performed during a call.
CallSurchargeTransfer,
/// Weight of output received through `seal_call` for the given size.
CallCopyOut(u32),
/// Weight of calling `seal_instantiate` for the given input and salt without output weight.
/// This includes the transfer as an instantiate without a value will always be below
/// the existential deposit and is disregarded as corner case.
InstantiateBase { input_data_len: u32, salt_len: u32 },
/// Weight of output received through `seal_instantiate` for the given size.
InstantiateCopyOut(u32),
/// Weight of calling `seal_hash_sha_256` for the given input size.
HashSha256(u32),
/// Weight of calling `seal_hash_keccak_256` for the given input size.
HashKeccak256(u32),
Loading full blame...