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 Debug, DispatchError,
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, Debug, 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, Debug, 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, Debug, 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, Debug, 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, Debug, 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, Debug, 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(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)]
155pub enum StorageDeposit<Balance> {
156 /// The transaction reduced storage consumption.
157 ///
158 /// This means that the specified amount of balance was transferred from the involved
159 /// deposit accounts to the origin.
160 Refund(Balance),
161 /// The transaction increased storage consumption.
162 ///
163 /// This means that the specified amount of balance was transferred from the origin
164 /// to the involved deposit accounts.
165 Charge(Balance),
166}
167
168impl<Balance: Zero> Default for StorageDeposit<Balance> {
169 fn default() -> Self {
170 Self::Charge(Zero::zero())
171 }
172}
173
174impl<Balance: Zero + Copy> StorageDeposit<Balance> {
175 /// Returns how much balance is charged or `0` in case of a refund.
176 pub fn charge_or_zero(&self) -> Balance {
177 match self {
178 Self::Charge(amount) => *amount,
179 Self::Refund(_) => Zero::zero(),
180 }
181 }
182
183 pub fn is_zero(&self) -> bool {
184 match self {
185 Self::Charge(amount) => amount.is_zero(),
186 Self::Refund(amount) => amount.is_zero(),
187 }
188 }
189}
190
191impl<Balance> StorageDeposit<Balance>
192where
193 Balance: Saturating + Ord + Copy,
194{
195 /// This is essentially a saturating signed add.
196 pub fn saturating_add(&self, rhs: &Self) -> Self {
197 use StorageDeposit::*;
198 match (self, rhs) {
199 (Charge(lhs), Charge(rhs)) => Charge(lhs.saturating_add(*rhs)),
200 (Refund(lhs), Refund(rhs)) => Refund(lhs.saturating_add(*rhs)),
201 (Charge(lhs), Refund(rhs)) =>
202 if lhs >= rhs {
203 Charge(lhs.saturating_sub(*rhs))
204 } else {
205 Refund(rhs.saturating_sub(*lhs))
206 },
207 (Refund(lhs), Charge(rhs)) =>
208 if lhs > rhs {
209 Refund(lhs.saturating_sub(*rhs))
210 } else {
211 Charge(rhs.saturating_sub(*lhs))
212 },
213 }
214 }
215
216 /// This is essentially a saturating signed sub.
217 pub fn saturating_sub(&self, rhs: &Self) -> Self {
218 use StorageDeposit::*;
219 match (self, rhs) {
220 (Charge(lhs), Refund(rhs)) => Charge(lhs.saturating_add(*rhs)),
221 (Refund(lhs), Charge(rhs)) => Refund(lhs.saturating_add(*rhs)),
222 (Charge(lhs), Charge(rhs)) =>
223 if lhs >= rhs {
224 Charge(lhs.saturating_sub(*rhs))
225 } else {
226 Refund(rhs.saturating_sub(*lhs))
227 },
228 (Refund(lhs), Refund(rhs)) =>
229 if lhs > rhs {
230 Refund(lhs.saturating_sub(*rhs))
231 } else {
232 Charge(rhs.saturating_sub(*lhs))
233 },
234 }
235 }
236
237 /// If the amount of deposit (this type) is constrained by a `limit` this calculates how
238 /// much balance (if any) is still available from this limit.
239 ///
240 /// # Note
241 ///
242 /// In case of a refund the return value can be larger than `limit`.
243 pub fn available(&self, limit: &Balance) -> Balance {
244 use StorageDeposit::*;
245 match self {
246 Charge(amount) => limit.saturating_sub(*amount),
247 Refund(amount) => limit.saturating_add(*amount),
248 }
249 }
250}