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}