ink_env/backend.rs
1// Copyright (C) Use Ink (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use ink_primitives::{
16 Address,
17 H256,
18 U256,
19 abi::AbiEncodeWith,
20 sol::SolResultEncode,
21 types::Environment,
22};
23use ink_storage_traits::Storable;
24pub use pallet_revive_uapi::ReturnFlags;
25
26use crate::{
27 DecodeDispatch,
28 DispatchError,
29 Result,
30 call::{
31 Call,
32 CallParams,
33 ConstructorReturnType,
34 CreateParams,
35 DelegateCall,
36 FromAddr,
37 LimitParamsV2,
38 utils::DecodeMessageResult,
39 },
40 event::{
41 Event,
42 TopicEncoder,
43 },
44 hash::{
45 CryptoHash,
46 HashOutput,
47 },
48};
49
50/// Environmental contract functionality that does not require `Environment`.
51pub trait EnvBackend {
52 /// Writes the value to the contract storage under the given storage key.
53 ///
54 /// Returns the size of the pre-existing value at the specified key if any.
55 fn set_contract_storage<K, V>(&mut self, key: &K, value: &V) -> Option<u32>
56 where
57 K: scale::Encode,
58 V: Storable;
59
60 /// Returns the value stored under the given storage key in the contract's storage if
61 /// any.
62 ///
63 /// # Errors
64 ///
65 /// - If the decoding of the typed value failed
66 fn get_contract_storage<K, R>(&mut self, key: &K) -> Result<Option<R>>
67 where
68 K: scale::Encode,
69 R: Storable;
70
71 /// Removes the `value` at `key`, returning the previous `value` at `key` from storage
72 /// if any.
73 ///
74 /// # Errors
75 ///
76 /// - If the decoding of the typed value failed
77 fn take_contract_storage<K, R>(&mut self, key: &K) -> Result<Option<R>>
78 where
79 K: scale::Encode,
80 R: Storable;
81
82 /// Returns the size of a value stored under the given storage key is returned if any.
83 fn contains_contract_storage<K>(&mut self, key: &K) -> Option<u32>
84 where
85 K: scale::Encode;
86
87 /// Clears the contract's storage key entry under the given storage key.
88 ///
89 /// Returns the size of the previously stored value at the specified key if any.
90 fn clear_contract_storage<K>(&mut self, key: &K) -> Option<u32>
91 where
92 K: scale::Encode;
93
94 /// Returns the execution input to the executed contract and decodes it as `T`.
95 ///
96 /// # Note
97 ///
98 /// - The input is the 4-bytes selector followed by the arguments of the called
99 /// function in their SCALE encoded representation.
100 /// - No prior interaction with the environment must take place before calling this
101 /// procedure.
102 ///
103 /// # Usage
104 ///
105 /// Normally contracts define their own `enum` dispatch types respective
106 /// to their exported constructors and messages that implement `scale::Decode`
107 /// according to the constructors or messages selectors and their arguments.
108 /// These `enum` dispatch types are then given to this procedure as the `T`.
109 ///
110 /// When using ink! users do not have to construct those enum dispatch types
111 /// themselves as they are normally generated by the ink! code generation
112 /// automatically.
113 ///
114 /// # Errors
115 ///
116 /// If the given `T` cannot be properly decoded from the expected input.
117 fn decode_input<T>(&mut self) -> core::result::Result<T, DispatchError>
118 where
119 T: DecodeDispatch;
120
121 /// Returns the value back to the caller of the executed contract.
122 ///
123 /// # Note
124 ///
125 /// Calling this method will end contract execution immediately.
126 /// It will return the given return value back to its caller.
127 ///
128 /// The `flags` parameter can be used to revert the state changes of the
129 /// entire execution if necessary.
130 #[cfg(not(feature = "std"))]
131 fn return_value<R>(&mut self, flags: ReturnFlags, return_value: &R) -> !
132 where
133 R: scale::Encode;
134
135 /// Returns the value back to the caller of the executed contract.
136 ///
137 /// # Note
138 ///
139 /// When the `std` feature is used, the contract is allowed to
140 /// return normally. This feature should only be used for integration tests.
141 ///
142 /// The `flags` parameter can be used to revert the state changes of the
143 /// entire execution if necessary.
144 #[cfg(feature = "std")]
145 fn return_value<R>(&mut self, flags: ReturnFlags, return_value: &R)
146 where
147 R: scale::Encode;
148
149 /// Returns the *Solidity ABI encoded* value back to the caller of the executed
150 /// contract.
151 ///
152 /// # Note
153 ///
154 /// This function stops the execution of the contract immediately.
155 fn return_value_solidity<R>(&mut self, flags: ReturnFlags, return_value: &R) -> !
156 where
157 R: for<'a> SolResultEncode<'a>;
158
159 /// Conducts the crypto hash of the given input and stores the result in `output`.
160 fn hash_bytes<H>(&mut self, input: &[u8], output: &mut <H as HashOutput>::Type)
161 where
162 H: CryptoHash;
163
164 /// Conducts the crypto hash of the given encoded input and stores the result in
165 /// `output`.
166 fn hash_encoded<H, T>(&mut self, input: &T, output: &mut <H as HashOutput>::Type)
167 where
168 H: CryptoHash,
169 T: scale::Encode;
170
171 /// Recovers the compressed ECDSA public key for given `signature` and `message_hash`,
172 /// and stores the result in `output`.
173 fn ecdsa_recover(
174 &mut self,
175 signature: &[u8; 65],
176 message_hash: &[u8; 32],
177 output: &mut [u8; 33],
178 ) -> Result<()>;
179
180 /// Retrieves an Ethereum address from the ECDSA compressed `pubkey`
181 /// and stores the result in `output`.
182 #[cfg(feature = "unstable-hostfn")]
183 fn ecdsa_to_eth_address(
184 &mut self,
185 pubkey: &[u8; 33],
186 output: &mut [u8; 20],
187 ) -> Result<()>;
188
189 /// Verifies a sr25519 signature.
190 ///
191 /// # Errors
192 ///
193 /// - If the signature verification failed.
194 ///
195 /// **WARNING**: this function is from the [unstable interface](https://github.com/paritytech/substrate/tree/master/frame/contracts#unstable-interfaces),
196 /// which is unsafe and normally is not available on production chains.
197 #[cfg(feature = "unstable-hostfn")]
198 fn sr25519_verify(
199 &mut self,
200 signature: &[u8; 64],
201 message: &[u8],
202 pub_key: &[u8; 32],
203 ) -> Result<()>;
204
205 /// Sets a new code hash for the current contract.
206 ///
207 /// This effectively replaces the code which is executed for this contract address.
208 ///
209 /// # Errors
210 ///
211 /// - If the supplied `code_hash` cannot be found on-chain.
212 #[cfg(feature = "unstable-hostfn")]
213 fn set_code_hash(&mut self, code_hash: &H256) -> Result<()>;
214
215 /// Returns the size of the buffer that is remaining in the backend.
216 fn remaining_buffer(&mut self) -> usize;
217}
218
219/// Environmental contract functionality.
220pub trait TypedEnvBackend: EnvBackend {
221 /// Returns the address of the caller of the executed contract.
222 ///
223 /// # Note
224 ///
225 /// For more details visit: [`caller`][`crate::caller`]
226 fn caller(&mut self) -> Address;
227
228 /// Returns the transferred value for the contract execution.
229 ///
230 /// # Note
231 ///
232 /// For more details visit: [`transferred_value`][`crate::transferred_value`]
233 fn transferred_value(&mut self) -> U256;
234
235 /// Returns the price for the specified amount of gas.
236 ///
237 /// # Note
238 ///
239 /// For more details visit: [`weight_to_fee`][`crate::weight_to_fee`]
240 fn weight_to_fee<E: Environment>(&mut self, gas: u64) -> E::Balance;
241
242 /// Returns the timestamp of the current block.
243 ///
244 /// # Note
245 ///
246 /// For more details visit: [`block_timestamp`][`crate::block_timestamp`]
247 fn block_timestamp<E: Environment>(&mut self) -> E::Timestamp;
248
249 /// Returns the address of the executed contract.
250 ///
251 /// # Note
252 ///
253 /// For more details visit: [`account_id`][`crate::account_id`]
254 fn account_id<E: Environment>(&mut self) -> E::AccountId;
255
256 /// Returns the address of the executed contract.
257 ///
258 /// # Note
259 ///
260 /// For more details visit: [`address`][`crate::address`]
261 fn address(&mut self) -> Address;
262
263 /// Returns the balance of the executed contract.
264 ///
265 /// # Note
266 ///
267 /// For more details visit: [`balance`][`crate::balance`]
268 fn balance(&mut self) -> U256;
269
270 /// Returns the current block number.
271 ///
272 /// # Note
273 ///
274 /// For more details visit: [`block_number`][`crate::block_number`]
275 fn block_number<E: Environment>(&mut self) -> E::BlockNumber;
276
277 /// Returns the minimum balance that is required for creating an account
278 /// (i.e. the chain's existential deposit).
279 ///
280 /// # Note
281 ///
282 /// For more details visit: [`minimum_balance`][`crate::minimum_balance`]
283 fn minimum_balance(&mut self) -> U256;
284
285 /// Emits an event with the given event data.
286 ///
287 /// # Note
288 ///
289 /// For more details visit: [`emit_event`][`crate::emit_event`]
290 fn emit_event<Evt, Abi>(&mut self, event: &Evt)
291 where
292 Evt: Event<Abi>,
293 Abi: TopicEncoder;
294
295 /// Invokes a contract message and returns its result.
296 ///
297 /// # Note
298 ///
299 /// **This will call into the latest `call_v2` host function.**
300 ///
301 /// For more details visit: [`invoke_contract`][`crate::invoke_contract`]
302 fn invoke_contract<E, Args, R, Abi>(
303 &mut self,
304 call_data: &CallParams<E, Call, Args, R, Abi>,
305 ) -> Result<ink_primitives::MessageResult<R>>
306 where
307 E: Environment,
308 Args: AbiEncodeWith<Abi>,
309 R: DecodeMessageResult<Abi>;
310
311 /// Invokes a contract message via delegate call and returns its result.
312 ///
313 /// # Note
314 ///
315 /// For more details visit:
316 /// [`invoke_contract_delegate`][`crate::invoke_contract_delegate`]
317 fn invoke_contract_delegate<E, Args, R, Abi>(
318 &mut self,
319 call_data: &CallParams<E, DelegateCall, Args, R, Abi>,
320 ) -> Result<ink_primitives::MessageResult<R>>
321 where
322 E: Environment,
323 Args: AbiEncodeWith<Abi>,
324 R: DecodeMessageResult<Abi>;
325
326 /// Instantiates another contract.
327 ///
328 /// # Note
329 ///
330 /// For more details visit: [`instantiate_contract`][`crate::instantiate_contract`]
331 fn instantiate_contract<E, ContractRef, Args, R, Abi>(
332 &mut self,
333 params: &CreateParams<E, ContractRef, LimitParamsV2, Args, R, Abi>,
334 ) -> Result<
335 ink_primitives::ConstructorResult<
336 <R as ConstructorReturnType<ContractRef, Abi>>::Output,
337 >,
338 >
339 where
340 E: Environment,
341 ContractRef: FromAddr + crate::ContractReverseReference,
342 <ContractRef as crate::ContractReverseReference>::Type:
343 crate::reflect::ContractConstructorDecoder,
344 Args: AbiEncodeWith<Abi>,
345 R: ConstructorReturnType<ContractRef, Abi>;
346
347 /// Terminates a smart contract.
348 ///
349 /// # Note
350 ///
351 /// For more details visit: [`terminate_contract`][`crate::terminate_contract`]
352 #[cfg(feature = "unstable-hostfn")]
353 fn terminate_contract(&mut self, beneficiary: Address) -> !;
354
355 /// Transfers value from the contract to the destination account ID.
356 ///
357 /// # Note
358 ///
359 /// For more details visit: [`transfer`][`crate::transfer`]
360 fn transfer<E>(&mut self, destination: Address, value: U256) -> Result<()>
361 where
362 E: Environment;
363
364 /// Checks whether a specified contract lives at `addr`.
365 ///
366 /// # Note
367 ///
368 /// For more details visit: [`is_contract`][`crate::is_contract`]
369 #[allow(clippy::wrong_self_convention)]
370 #[cfg(feature = "unstable-hostfn")]
371 fn is_contract(&mut self, account: &Address) -> bool;
372
373 /// Checks whether the caller of the current contract is the origin of the whole call
374 /// stack.
375 ///
376 /// # Note
377 ///
378 /// For more details visit: [`caller_is_origin`][`crate::caller_is_origin`]
379 fn caller_is_origin<E>(&mut self) -> bool
380 where
381 E: Environment;
382
383 /// Checks whether the caller of the current contract is root.
384 ///
385 /// # Note
386 ///
387 /// For more details visit: [`caller_is_root`][`crate::caller_is_root`]
388 fn caller_is_root<E>(&mut self) -> bool
389 where
390 E: Environment;
391
392 /// Retrieves the code hash of the contract at the given `account` id.
393 ///
394 /// # Note
395 ///
396 /// For more details visit: [`code_hash`][`crate::code_hash`]
397 fn code_hash(&mut self, account: &Address) -> Result<H256>;
398
399 /// Retrieves the code hash of the currently executing contract.
400 ///
401 /// # Note
402 ///
403 /// For more details visit: [`own_code_hash`][`crate::own_code_hash`]
404 fn own_code_hash(&mut self) -> Result<H256>;
405
406 /// Execute an XCM message locally, using the contract's address as the origin.
407 ///
408 /// # Note
409 ///
410 /// For more details visit: [`xcm`][`crate::xcm_execute`].
411 #[cfg(all(feature = "xcm", feature = "unstable-hostfn"))]
412 fn xcm_execute<E, Call>(&mut self, msg: &xcm::VersionedXcm<Call>) -> Result<()>
413 where
414 E: Environment,
415 Call: scale::Encode;
416
417 /// Send an XCM message, using the contract's address as the origin.
418 ///
419 /// # Note
420 ///
421 /// For more details visit: [`xcm`][`crate::xcm_send`].
422 #[cfg(all(feature = "xcm", feature = "unstable-hostfn"))]
423 fn xcm_send<E, Call>(
424 &mut self,
425 dest: &xcm::VersionedLocation,
426 msg: &xcm::VersionedXcm<Call>,
427 ) -> Result<xcm::v4::XcmHash>
428 where
429 E: Environment,
430 Call: scale::Encode;
431}