referrerpolicy=no-referrer-when-downgrade

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}