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