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