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