// This file is part of Substrate. // Copyright (C) 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. //! A crate that hosts a common definitions that are relevant for the pallet-contracts. use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::weights::Weight; use pallet_contracts_uapi::ReturnFlags; use scale_info::TypeInfo; use sp_runtime::{ traits::{Saturating, Zero}, DispatchError, RuntimeDebug, }; use sp_std::prelude::*; /// Result type of a `bare_call` or `bare_instantiate` call as well as `ContractsApi::call` and /// `ContractsApi::instantiate`. /// /// It contains the execution result together with some auxiliary information. /// /// #Note /// /// It has been extended to include `events` at the end of the struct while not bumping the /// `ContractsApi` version. Therefore when SCALE decoding a `ContractResult` its trailing data /// should be ignored to avoid any potential compatibility issues. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ContractResult { /// How much weight was consumed during execution. pub gas_consumed: Weight, /// How much weight is required as gas limit in order to execute this call. /// /// This value should be used to determine the weight limit for on-chain execution. /// /// # Note /// /// This can only different from [`Self::gas_consumed`] when weight pre charging /// is used. Currently, only `seal_call_runtime` makes use of pre charging. /// Additionally, any `seal_call` or `seal_instantiate` makes use of pre-charging /// when a non-zero `gas_limit` argument is supplied. pub gas_required: Weight, /// How much balance was paid by the origin into the contract's deposit account in order to /// pay for storage. /// /// The storage deposit is never actually charged from the origin in case of [`Self::result`] /// is `Err`. This is because on error all storage changes are rolled back including the /// payment of the deposit. pub storage_deposit: StorageDeposit, /// An optional debug message. This message is only filled when explicitly requested /// by the code that calls into the contract. Otherwise it is empty. /// /// The contained bytes are valid UTF-8. This is not declared as `String` because /// this type is not allowed within the runtime. /// /// Clients should not make any assumptions about the format of the buffer. /// They should just display it as-is. It is **not** only a collection of log lines /// provided by a contract but a formatted buffer with different sections. /// /// # Note /// /// The debug message is never generated during on-chain execution. It is reserved for /// RPC calls. pub debug_message: Vec, /// The execution result of the wasm code. pub result: R, /// The events that were emitted during execution. It is an option as event collection is /// optional. pub events: Option>, } /// Result type of a `bare_call` call as well as `ContractsApi::call`. pub type ContractExecResult = ContractResult, Balance, EventRecord>; /// Result type of a `bare_instantiate` call as well as `ContractsApi::instantiate`. pub type ContractInstantiateResult = ContractResult, DispatchError>, Balance, EventRecord>; /// Result type of a `bare_code_upload` call. pub type CodeUploadResult = Result, DispatchError>; /// Result type of a `get_storage` call. pub type GetStorageResult = Result>, ContractAccessError>; /// The possible errors that can happen querying the storage of a contract. #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo)] pub enum ContractAccessError { /// The given address doesn't point to a contract. DoesntExist, /// Storage key cannot be decoded from the provided input data. KeyDecodingFailed, /// Storage is migrating. Try again later. MigrationInProgress, } /// Output of a contract call or instantiation which ran to completion. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ExecReturnValue { /// Flags passed along by `seal_return`. Empty when `seal_return` was never called. pub flags: ReturnFlags, /// Buffer passed along by `seal_return`. Empty when `seal_return` was never called. pub data: Vec, } impl ExecReturnValue { /// The contract did revert all storage changes. pub fn did_revert(&self) -> bool { self.flags.contains(ReturnFlags::REVERT) } } /// The result of a successful contract instantiation. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct InstantiateReturnValue { /// The output of the called constructor. pub result: ExecReturnValue, /// The account id of the new contract. pub account_id: AccountId, } /// The result of successfully uploading a contract. #[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo)] pub struct CodeUploadReturnValue { /// The key under which the new code is stored. pub code_hash: CodeHash, /// The deposit that was reserved at the caller. Is zero when the code already existed. pub deposit: Balance, } /// Reference to an existing code hash or a new wasm module. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum Code { /// A wasm module as raw bytes. Upload(Vec), /// The code hash of an on-chain wasm blob. Existing(Hash), } /// The amount of balance that was either charged or refunded in order to pay for storage. #[derive( Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo, )] pub enum StorageDeposit { /// The transaction reduced storage consumption. /// /// This means that the specified amount of balance was transferred from the involved /// deposit accounts to the origin. Refund(Balance), /// The transaction increased storage consumption. /// /// This means that the specified amount of balance was transferred from the origin /// to the involved deposit accounts. Charge(Balance), } impl Default for StorageDeposit { fn default() -> Self { Self::Charge(Zero::zero()) } } impl StorageDeposit { /// Returns how much balance is charged or `0` in case of a refund. pub fn charge_or_zero(&self) -> Balance { match self { Self::Charge(amount) => *amount, Self::Refund(_) => Zero::zero(), } } pub fn is_zero(&self) -> bool { match self { Self::Charge(amount) => amount.is_zero(), Self::Refund(amount) => amount.is_zero(), } } } impl StorageDeposit where Balance: Saturating + Ord + Copy, { /// This is essentially a saturating signed add. pub fn saturating_add(&self, rhs: &Self) -> Self { use StorageDeposit::*; match (self, rhs) { (Charge(lhs), Charge(rhs)) => Charge(lhs.saturating_add(*rhs)), (Refund(lhs), Refund(rhs)) => Refund(lhs.saturating_add(*rhs)), (Charge(lhs), Refund(rhs)) => if lhs >= rhs { Charge(lhs.saturating_sub(*rhs)) } else { Refund(rhs.saturating_sub(*lhs)) }, (Refund(lhs), Charge(rhs)) => if lhs > rhs { Refund(lhs.saturating_sub(*rhs)) } else { Charge(rhs.saturating_sub(*lhs)) }, } } /// This is essentially a saturating signed sub. pub fn saturating_sub(&self, rhs: &Self) -> Self { use StorageDeposit::*; match (self, rhs) { (Charge(lhs), Refund(rhs)) => Charge(lhs.saturating_add(*rhs)), (Refund(lhs), Charge(rhs)) => Refund(lhs.saturating_add(*rhs)), (Charge(lhs), Charge(rhs)) => if lhs >= rhs { Charge(lhs.saturating_sub(*rhs)) } else { Refund(rhs.saturating_sub(*lhs)) }, (Refund(lhs), Refund(rhs)) => if lhs > rhs { Refund(lhs.saturating_sub(*rhs)) } else { Charge(rhs.saturating_sub(*lhs)) }, } } /// If the amount of deposit (this type) is constrained by a `limit` this calculates how /// much balance (if any) is still available from this limit. /// /// # Note /// /// In case of a refund the return value can be larger than `limit`. pub fn available(&self, limit: &Balance) -> Balance { use StorageDeposit::*; match self { Charge(amount) => limit.saturating_sub(*amount), Refund(amount) => limit.saturating_add(*amount), } } }