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}