pallet_contracts_primitives/lib.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! A crate that hosts a common definitions that are relevant for the pallet-contracts.
19
20#![cfg_attr(not(feature = "std"), no_std)]
21
22use bitflags::bitflags;
23use codec::{Decode, Encode, MaxEncodedLen};
24use scale_info::TypeInfo;
25use sp_runtime::{
26 traits::{Saturating, Zero},
27 DispatchError, RuntimeDebug,
28};
29use sp_std::prelude::*;
30use sp_weights::Weight;
31
32/// Result type of a `bare_call` or `bare_instantiate` call as well as `ContractsApi::call` and
33/// `ContractsApi::instantiate`.
34///
35/// It contains the execution result together with some auxiliary information.
36///
37/// #Note
38///
39/// It has been extended to include `events` at the end of the struct while not bumping the
40/// `ContractsApi` version. Therefore when SCALE decoding a `ContractResult` its trailing data
41/// should be ignored to avoid any potential compatibility issues.
42#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
43pub struct ContractResult<R, Balance, EventRecord> {
44 /// How much weight was consumed during execution.
45 pub gas_consumed: Weight,
46 /// How much weight is required as gas limit in order to execute this call.
47 ///
48 /// This value should be used to determine the weight limit for on-chain execution.
49 ///
50 /// # Note
51 ///
52 /// This can only different from [`Self::gas_consumed`] when weight pre charging
53 /// is used. Currently, only `seal_call_runtime` makes use of pre charging.
54 /// Additionally, any `seal_call` or `seal_instantiate` makes use of pre-charging
55 /// when a non-zero `gas_limit` argument is supplied.
56 pub gas_required: Weight,
57 /// How much balance was paid by the origin into the contract's deposit account in order to
58 /// pay for storage.
59 ///
60 /// The storage deposit is never actually charged from the origin in case of [`Self::result`]
61 /// is `Err`. This is because on error all storage changes are rolled back including the
62 /// payment of the deposit.
63 pub storage_deposit: StorageDeposit<Balance>,
64 /// An optional debug message. This message is only filled when explicitly requested
65 /// by the code that calls into the contract. Otherwise it is empty.
66 ///
67 /// The contained bytes are valid UTF-8. This is not declared as `String` because
68 /// this type is not allowed within the runtime.
69 ///
70 /// Clients should not make any assumptions about the format of the buffer.
71 /// They should just display it as-is. It is **not** only a collection of log lines
72 /// provided by a contract but a formatted buffer with different sections.
73 ///
74 /// # Note
75 ///
76 /// The debug message is never generated during on-chain execution. It is reserved for
77 /// RPC calls.
78 pub debug_message: Vec<u8>,
79 /// The execution result of the wasm code.
80 pub result: R,
81 /// The events that were emitted during execution. It is an option as event collection is
82 /// optional.
83 pub events: Option<Vec<EventRecord>>,
84}
85
86/// Result type of a `bare_call` call as well as `ContractsApi::call`.
87pub type ContractExecResult<Balance, EventRecord> =
88 ContractResult<Result<ExecReturnValue, DispatchError>, Balance, EventRecord>;
89
90/// Result type of a `bare_instantiate` call as well as `ContractsApi::instantiate`.
91pub type ContractInstantiateResult<AccountId, Balance, EventRecord> =
92 ContractResult<Result<InstantiateReturnValue<AccountId>, DispatchError>, Balance, EventRecord>;
93
94/// Result type of a `bare_code_upload` call.
95pub type CodeUploadResult<CodeHash, Balance> =
96 Result<CodeUploadReturnValue<CodeHash, Balance>, DispatchError>;
97
98/// Result type of a `get_storage` call.
99pub type GetStorageResult = Result<Option<Vec<u8>>, ContractAccessError>;
100
101/// The possible errors that can happen querying the storage of a contract.
102#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo)]
103pub enum ContractAccessError {
104 /// The given address doesn't point to a contract.
105 DoesntExist,
106 /// Storage key cannot be decoded from the provided input data.
107 KeyDecodingFailed,
108 /// Storage is migrating. Try again later.
109 MigrationInProgress,
110}
111
112bitflags! {
113 /// Flags used by a contract to customize exit behaviour.
114 #[derive(Encode, Decode, TypeInfo)]
115 pub struct ReturnFlags: u32 {
116 /// If this bit is set all changes made by the contract execution are rolled back.
117 const REVERT = 0x0000_0001;
118 }
119}
120
121/// Output of a contract call or instantiation which ran to completion.
122#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
123pub struct ExecReturnValue {
124 /// Flags passed along by `seal_return`. Empty when `seal_return` was never called.
125 pub flags: ReturnFlags,
126 /// Buffer passed along by `seal_return`. Empty when `seal_return` was never called.
127 pub data: Vec<u8>,
128}
129
130impl ExecReturnValue {
131 /// The contract did revert all storage changes.
132 pub fn did_revert(&self) -> bool {
133 self.flags.contains(ReturnFlags::REVERT)
134 }
135}
136
137/// The result of a successful contract instantiation.
138#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
139pub struct InstantiateReturnValue<AccountId> {
140 /// The output of the called constructor.
141 pub result: ExecReturnValue,
142 /// The account id of the new contract.
143 pub account_id: AccountId,
144}
145
146/// The result of successfully uploading a contract.
147#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo)]
148pub struct CodeUploadReturnValue<CodeHash, Balance> {
149 /// The key under which the new code is stored.
150 pub code_hash: CodeHash,
151 /// The deposit that was reserved at the caller. Is zero when the code already existed.
152 pub deposit: Balance,
153}
154
155/// Reference to an existing code hash or a new wasm module.
156#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
157pub enum Code<Hash> {
158 /// A wasm module as raw bytes.
159 Upload(Vec<u8>),
160 /// The code hash of an on-chain wasm blob.
161 Existing(Hash),
162}
163
164/// The amount of balance that was either charged or refunded in order to pay for storage.
165#[derive(
166 Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo,
167)]
168pub enum StorageDeposit<Balance> {
169 /// The transaction reduced storage consumption.
170 ///
171 /// This means that the specified amount of balance was transferred from the involved
172 /// deposit accounts to the origin.
173 Refund(Balance),
174 /// The transaction increased storage consumption.
175 ///
176 /// This means that the specified amount of balance was transferred from the origin
177 /// to the involved deposit accounts.
178 Charge(Balance),
179}
180
181impl<Balance: Zero> Default for StorageDeposit<Balance> {
182 fn default() -> Self {
183 Self::Charge(Zero::zero())
184 }
185}
186
187impl<Balance: Zero + Copy> StorageDeposit<Balance> {
188 /// Returns how much balance is charged or `0` in case of a refund.
189 pub fn charge_or_zero(&self) -> Balance {
190 match self {
191 Self::Charge(amount) => *amount,
192 Self::Refund(_) => Zero::zero(),
193 }
194 }
195
196 pub fn is_zero(&self) -> bool {
197 match self {
198 Self::Charge(amount) => amount.is_zero(),
199 Self::Refund(amount) => amount.is_zero(),
200 }
201 }
202}
203
204impl<Balance> StorageDeposit<Balance>
205where
206 Balance: Saturating + Ord + Copy,
207{
208 /// This is essentially a saturating signed add.
209 pub fn saturating_add(&self, rhs: &Self) -> Self {
210 use StorageDeposit::*;
211 match (self, rhs) {
212 (Charge(lhs), Charge(rhs)) => Charge(lhs.saturating_add(*rhs)),
213 (Refund(lhs), Refund(rhs)) => Refund(lhs.saturating_add(*rhs)),
214 (Charge(lhs), Refund(rhs)) =>
215 if lhs >= rhs {
216 Charge(lhs.saturating_sub(*rhs))
217 } else {
218 Refund(rhs.saturating_sub(*lhs))
219 },
220 (Refund(lhs), Charge(rhs)) =>
221 if lhs > rhs {
222 Refund(lhs.saturating_sub(*rhs))
223 } else {
224 Charge(rhs.saturating_sub(*lhs))
225 },
226 }
227 }
228
229 /// This is essentially a saturating signed sub.
230 pub fn saturating_sub(&self, rhs: &Self) -> Self {
231 use StorageDeposit::*;
232 match (self, rhs) {
233 (Charge(lhs), Refund(rhs)) => Charge(lhs.saturating_add(*rhs)),
234 (Refund(lhs), Charge(rhs)) => Refund(lhs.saturating_add(*rhs)),
235 (Charge(lhs), Charge(rhs)) =>
236 if lhs >= rhs {
237 Charge(lhs.saturating_sub(*rhs))
238 } else {
239 Refund(rhs.saturating_sub(*lhs))
240 },
241 (Refund(lhs), Refund(rhs)) =>
242 if lhs > rhs {
243 Refund(lhs.saturating_sub(*rhs))
244 } else {
245 Charge(rhs.saturating_sub(*lhs))
246 },
247 }
248 }
249
250 /// If the amount of deposit (this type) is constrained by a `limit` this calculates how
251 /// much balance (if any) is still available from this limit.
252 ///
253 /// # Note
254 ///
255 /// In case of a refund the return value can be larger than `limit`.
256 pub fn available(&self, limit: &Balance) -> Balance {
257 use StorageDeposit::*;
258 match self {
259 Charge(amount) => limit.saturating_sub(*amount),
260 Refund(amount) => limit.saturating_add(*amount),
261 }
262 }
263}