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