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}