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}