ink_primitives/reflect/
dispatch.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 pallet_revive_uapi::ReturnFlags;
16
17use crate::abi::Abi;
18
19/// Stores various information of the respective dispatchable ink! message.
20///
21/// # Note
22///
23/// This trait is implemented by ink! for every dispatchable ink! message
24/// of the root ink! smart contract. The `ID` used in the trait reflects the
25/// chosen or derived selector of the dispatchable ink! message.
26///
27/// # Usage
28///
29/// ```
30/// # use ink::reflect::DispatchableMessageInfo;
31/// # use ink::{selector_id, selector_bytes};
32///
33/// #[ink::contract]
34/// pub mod contract {
35///     #[ink(storage)]
36///     pub struct Contract {}
37///
38///     impl Contract {
39///         #[ink(constructor)]
40///         pub fn constructor() -> Self {
41///             Contract {}
42///         }
43///
44///         #[ink(message)]
45///         pub fn message1(&self) {}
46///
47///         #[ink(message, payable, selector = 0xC0DECAFE)]
48///         pub fn message2(&mut self, input1: i32, input2: i64) -> (bool, i32) {
49///             unimplemented!()
50///         }
51///     }
52/// }
53///
54/// use contract::Contract;
55///
56/// /// Asserts that the message with the selector `ID` has the following properties.
57/// ///
58/// /// # Note
59/// ///
60/// /// The `In` and `Out` generic parameters describe the input and output types.
61/// fn assert_message_info<In, Out, const ID: u32>(
62///     mutates: bool,
63///     payable: bool,
64///     selector: [u8; 4],
65///     label: &str,
66/// ) where
67///     Contract: DispatchableMessageInfo<{ ID }, Input = In, Output = Out>,
68/// {
69///     assert_eq!(
70///         <Contract as DispatchableMessageInfo<{ ID }>>::MUTATES,
71///         mutates
72///     );
73///     assert_eq!(
74///         <Contract as DispatchableMessageInfo<{ ID }>>::PAYABLE,
75///         payable
76///     );
77///     assert_eq!(
78///         <Contract as DispatchableMessageInfo<{ ID }>>::SELECTOR,
79///         selector,
80///     );
81///     assert_eq!(<Contract as DispatchableMessageInfo<{ ID }>>::LABEL, label,);
82/// }
83///
84/// fn main() {
85///     assert_message_info::<(), (), { selector_id!("message1") }>(
86///         false,
87///         false,
88///         selector_bytes!("message1"),
89///         "message1",
90///     );
91///     assert_message_info::<(i32, i64), (bool, i32), 0xC0DECAFE_u32>(
92///         true,
93///         true,
94///         [0xC0, 0xDE, 0xCA, 0xFE],
95///         "message2",
96///     );
97/// }
98/// ```
99pub trait DispatchableMessageInfo<const ID: u32> {
100    /// Reflects the input types of the dispatchable ink! message.
101    type Input;
102    /// Reflects the output type of the dispatchable ink! message.
103    type Output;
104    /// The ink! storage struct type.
105    type Storage;
106
107    /// The closure that can be used to dispatch into the dispatchable ink! message.
108    ///
109    /// # Note
110    ///
111    /// We unify `&self` and `&mut self` ink! messages here and always take a `&mut self`.
112    /// This is mainly done for simplification but also because we can easily convert from
113    /// `&mut self` to `&self` with our current dispatch codegen architecture.
114    const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output;
115
116    /// The closure for decoding message input.
117    const DECODE: fn(
118        &mut &[::core::primitive::u8],
119    ) -> Result<Self::Input, DispatchError>;
120
121    /// closure for returning per encoding todo: docs
122    #[cfg(not(feature = "std"))]
123    const RETURN: fn(ReturnFlags, Self::Output) -> !;
124
125    /// closure for returning per encoding todo: docs
126    #[cfg(feature = "std")]
127    const RETURN: fn(ReturnFlags, Self::Output) -> ();
128
129    /// Yields `true` if the dispatchable ink! message mutates the ink! storage.
130    const MUTATES: bool;
131    /// Yields `true` if the dispatchable ink! message is payable.
132    const PAYABLE: bool;
133    /// The selector of the dispatchable ink! message.
134    const SELECTOR: [u8; 4];
135    /// The label of the dispatchable ink! message.
136    const LABEL: &'static str;
137    /// The ABI spec for the decoding the message call.
138    const ABI: Abi;
139}
140
141/// Stores various information of the respective dispatchable ink! constructor.
142///
143/// # Note
144///
145/// This trait is implemented by ink! for every dispatchable ink! constructor
146/// of the root ink! smart contract. The `ID` used in the trait reflects the
147/// chosen or derived selector of the dispatchable ink! constructor.
148///
149/// # Usage
150///
151/// ```
152/// # use ink::reflect::DispatchableConstructorInfo;
153/// # use ink::{selector_id, selector_bytes};
154///
155/// #[ink::contract]
156/// pub mod contract {
157///     #[ink(storage)]
158///     pub struct Contract {}
159///
160///     impl Contract {
161///         #[ink(constructor)]
162///         pub fn constructor1() -> Self {
163///             Contract {}
164///         }
165///
166///         #[ink(constructor, selector = 0xC0DECAFE)]
167///         pub fn constructor2(input1: i32, input2: i64) -> Self {
168///             Contract {}
169///         }
170///
171///         #[ink(message)]
172///         pub fn message(&self) {}
173///     }
174/// }
175///
176/// use contract::Contract;
177///
178/// /// Asserts that the constructor with the selector `ID` has the following properties.
179/// ///
180/// /// # Note
181/// ///
182/// /// The `In` and `Out` generic parameters describe the input and output types.
183/// fn assert_constructor_info<In, const ID: u32>(selector: [u8; 4], label: &str)
184/// where
185///     Contract: DispatchableConstructorInfo<{ ID }, Input = In>,
186/// {
187///     assert_eq!(
188///         <Contract as DispatchableConstructorInfo<{ ID }>>::SELECTOR,
189///         Some(selector),
190///     );
191///     assert_eq!(
192///         <Contract as DispatchableConstructorInfo<{ ID }>>::LABEL,
193///         label,
194///     );
195/// }
196///
197/// fn main() {
198///     assert_constructor_info::<(), { selector_id!("constructor1") }>(
199///         selector_bytes!("constructor1"),
200///         "constructor1",
201///     );
202///     assert_constructor_info::<(i32, i64), 0xC0DECAFE_u32>(
203///         [0xC0, 0xDE, 0xCA, 0xFE],
204///         "constructor2",
205///     );
206/// }
207/// ```
208pub trait DispatchableConstructorInfo<const ID: u32> {
209    /// Reflects the input types of the dispatchable ink! constructor.
210    type Input;
211    /// The ink! storage struct type.
212    type Storage;
213    /// Reflects the output type of the dispatchable ink! constructor.
214    type Output;
215    /// The type of the error returned from the constructor.
216    /// Infallible constructors will have `()` as the error type.
217    type Error;
218
219    /// True if the constructor returns a `Result`.
220    const IS_RESULT: bool;
221
222    /// The closure that can be used to dispatch into the dispatchable ink! constructor.
223    const CALLABLE: fn(Self::Input) -> Self::Output;
224
225    /// The closure for decoding constructor input.
226    const DECODE: fn(
227        &mut &[::core::primitive::u8],
228    ) -> Result<Self::Input, DispatchError>;
229
230    /// The closure for returning return data.
231    #[cfg(not(feature = "std"))]
232    const RETURN: fn(ReturnFlags, Result<(), &Self::Error>) -> !;
233
234    /// The closure for returning return data.
235    #[cfg(feature = "std")]
236    const RETURN: fn(ReturnFlags, Result<(), &Self::Error>) -> ();
237
238    /// Yields `true` if the dispatchable ink! constructor is payable.
239    const PAYABLE: bool;
240
241    /// The selector (if any) of the dispatchable ink! constructor.
242    const SELECTOR: Option<[u8; 4]>;
243
244    /// The label of the dispatchable ink! constructor.
245    const LABEL: &'static str;
246
247    /// The ABI spec for the decoding the constructor call.
248    const ABI: Abi;
249}
250
251mod private {
252    /// Seals the implementation of `ConstructorReturnType`.
253    pub trait Sealed {}
254}
255
256/// Guards against using invalid contract initializer types.
257///
258/// # Note
259///
260/// Currently, the only allowed types are `()` and `Result<(), E>`
261/// where `E` is some unspecified error type.
262/// If the contract initializer returns `Result::Err` the utility
263/// method that is used to initialize an ink! smart contract will
264/// revert the state of the contract instantiation.
265pub trait ConstructorOutput<C>: private::Sealed {
266    /// Is `true` if `Self` is `Result<C, E>`.
267    const IS_RESULT: bool = false;
268
269    /// The error type of the constructor return type.
270    ///
271    /// # Note
272    ///
273    /// For infallible constructors this is `()` whereas for fallible
274    /// constructors this is the actual return error type. Since we only ever
275    /// return a value in case of `Result::Err` the `Result::Ok` value type
276    /// does not matter.
277    type Error;
278
279    /// Converts the return value into a `Result` instance.
280    ///
281    /// # Note
282    ///
283    /// For infallible constructor returns this always yields `Ok`.
284    fn as_result(&self) -> Result<&C, &Self::Error>;
285}
286
287/// Stores the actual value of the constructor return type.
288///
289/// # Note
290///
291/// Currently, the only allowed types are `()` and `Result<(), E>`
292/// where `E` is some unspecified error type.
293/// If the contract initializer returns `Result::Err` the utility
294/// method that is used to initialize an ink! smart contract will
295/// revert the state of the contract instantiation.
296pub struct ConstructorOutputValue<T>(T);
297
298impl<T> ConstructorOutputValue<T> {
299    /// Stores the actual value of the constructor return type.
300    pub fn new(val: T) -> Self {
301        Self(val)
302    }
303}
304
305impl<T> private::Sealed for ConstructorOutputValue<T> {}
306
307impl<C> ConstructorOutput<C> for ConstructorOutputValue<C> {
308    type Error = &'static ();
309
310    #[inline(always)]
311    fn as_result(&self) -> Result<&C, &Self::Error> {
312        Ok(&self.0)
313    }
314}
315
316impl<C, E> ConstructorOutput<C> for ConstructorOutputValue<Result<C, E>> {
317    const IS_RESULT: bool = true;
318    type Error = E;
319
320    #[inline(always)]
321    fn as_result(&self) -> Result<&C, &Self::Error> {
322        self.0.as_ref()
323    }
324}
325
326/// Generated type used to decode all dispatchable ink! messages of the ink! smart
327/// contract.
328///
329/// # Note
330///
331/// The decoder follows the ink! calling ABI where all ink! message calls start with
332/// 4 bytes dedicated to the ink! message selector followed by the SCALE encoded
333/// parameters.
334///
335/// # Usage
336///
337/// ```
338/// # use ink::reflect::ContractMessageDecoder;
339/// # use ink::selector_bytes;
340/// # use scale::{Encode, Decode};
341///
342/// #[ink::contract]
343/// pub mod contract {
344///     #[ink(storage)]
345///     pub struct Contract {}
346///
347///     impl Contract {
348///         #[ink(constructor)]
349///         pub fn constructor() -> Self {
350///             Self {}
351///         }
352///
353///         #[ink(message)]
354///         pub fn message1(&self) {}
355///
356///         #[ink(message)]
357///         pub fn message2(&self, input1: bool, input2: i32) {}
358///     }
359/// }
360///
361/// use contract::Contract;
362/// use ink::env::DecodeDispatch;
363///
364/// fn main() {
365///     // Call to `message1` without input parameters.
366///     {
367///         let mut input_bytes = Vec::new();
368///         input_bytes.extend(selector_bytes!("message1"));
369///         assert!(
370///             <<Contract as ContractMessageDecoder>::Type as DecodeDispatch>::decode_dispatch(
371///                 &mut &input_bytes[..]
372///             )
373///             .is_ok()
374///         );
375///     }
376///     // Call to `message2` with 2 parameters.
377///     {
378///         let mut input_bytes = Vec::new();
379///         input_bytes.extend(selector_bytes!("message2"));
380///         input_bytes.extend(true.encode());
381///         input_bytes.extend(42i32.encode());
382///         assert!(
383///             <<Contract as ContractMessageDecoder>::Type as DecodeDispatch>::decode_dispatch(
384///                 &mut &input_bytes[..]
385///             )
386///             .is_ok()
387///         );
388///     }
389///     // Call with invalid ink! message selector.
390///     {
391///         let mut input_bytes = Vec::new();
392///         input_bytes.extend(selector_bytes!("non_existing_message"));
393///         assert!(
394///             <<Contract as ContractMessageDecoder>::Type as DecodeDispatch>::decode_dispatch(
395///                 &mut &input_bytes[..]
396///             )
397///             .is_err()
398///         );
399///     }
400///     // Call with invalid ink! message parameters.
401///     {
402///         let mut input_bytes = Vec::new();
403///         input_bytes.extend(selector_bytes!("message2"));
404///         assert!(
405///             <<Contract as ContractMessageDecoder>::Type as DecodeDispatch>::decode_dispatch(
406///                 &mut &input_bytes[..]
407///             )
408///             .is_err()
409///         );
410///     }
411/// }
412/// ```
413pub trait ContractMessageDecoder {
414    /// The ink! smart contract message decoder type.
415    type Type: DecodeDispatch + ExecuteDispatchable;
416}
417
418/// Generated type used to decode all dispatchable ink! constructors of the ink! smart
419/// contract.
420///
421/// # Note
422///
423/// The decoder follows the ink! calling ABI where all ink! constructor calls start with
424/// 4 bytes dedicated to the ink! constructor selector followed by the SCALE encoded
425/// parameters.
426///
427/// # Usage
428///
429/// ```
430/// # use ink::reflect::ContractConstructorDecoder;
431/// # use ink::selector_bytes;
432/// # use scale::{Encode, Decode};
433///
434/// #[ink::contract]
435/// pub mod contract {
436///     #[ink(storage)]
437///     pub struct Contract {}
438///
439///     impl Contract {
440///         #[ink(constructor)]
441///         pub fn constructor1() -> Self {
442///             Self {}
443///         }
444///
445///         #[ink(constructor)]
446///         pub fn constructor2(input1: bool, input2: i32) -> Self {
447///             Self {}
448///         }
449///
450///         #[ink(message)]
451///         pub fn message(&self) {}
452///     }
453/// }
454///
455/// use contract::Contract;
456/// use ink::env::DecodeDispatch;
457///
458/// fn main() {
459///     // Call to `constructor1` without input parameters.
460///     {
461///         let mut input_bytes = Vec::new();
462///         input_bytes.extend(selector_bytes!("constructor1"));
463///         assert!(
464///             <<Contract as ContractConstructorDecoder>::Type as DecodeDispatch>::decode_dispatch(
465///                 &mut &input_bytes[..]
466///             )
467///             .is_ok()
468///         );
469///     }
470///     // Call to `constructor2` with 2 parameters.
471///     {
472///         let mut input_bytes = Vec::new();
473///         input_bytes.extend(selector_bytes!("constructor2"));
474///         input_bytes.extend(true.encode());
475///         input_bytes.extend(42i32.encode());
476///         assert!(
477///             <<Contract as ContractConstructorDecoder>::Type as DecodeDispatch>::decode_dispatch(
478///                 &mut &input_bytes[..]
479///             )
480///             .is_ok()
481///         );
482///     }
483///     // Call with invalid ink! constructor selector.
484///     {
485///         let mut input_bytes = Vec::new();
486///         input_bytes.extend(selector_bytes!("non_existing_constructor"));
487///         assert!(
488///             <<Contract as ContractConstructorDecoder>::Type as DecodeDispatch>::decode_dispatch(
489///                 &mut &input_bytes[..]
490///             )
491///             .is_err()
492///         );
493///     }
494///     // Call with invalid ink! constructor parameters.
495///     {
496///         let mut input_bytes = Vec::new();
497///         input_bytes.extend(selector_bytes!("constructor2"));
498///         assert!(
499///             <<Contract as ContractConstructorDecoder>::Type as DecodeDispatch>::decode_dispatch(
500///                 &mut &input_bytes[..]
501///             )
502///             .is_err()
503///         );
504///     }
505/// }
506/// ```
507pub trait ContractConstructorDecoder {
508    /// The ink! smart contract constructor decoder type.
509    type Type: DecodeDispatch + ExecuteDispatchable;
510}
511
512/// Starts the execution of the respective ink! message or constructor call.
513///
514/// # Note
515///
516/// Implemented by the ink! smart contract message or constructor decoder.
517pub trait ExecuteDispatchable {
518    /// Executes the ink! smart contract message or constructor.
519    fn execute_dispatchable(self) -> Result<(), DispatchError>;
520}
521
522/// An error that can occur during dispatch of ink! dispatchables.
523/// todo: add tests for other errors beside `PaidUnpayableMessage`
524#[derive(Debug, Copy, Clone, PartialEq, Eq)]
525pub enum DispatchError {
526    /// Failed to decode into a valid dispatch selector.
527    InvalidSelector,
528    /// The decoded selector is not known to the dispatch decoder.
529    UnknownSelector,
530    /// Failed to decode the parameters for the selected dispatchable.
531    InvalidParameters,
532    /// Failed to read execution input for the dispatchable.
533    CouldNotReadInput,
534    /// Invalidly paid an unpayable dispatchable.
535    PaidUnpayableMessage,
536}
537
538impl core::fmt::Display for DispatchError {
539    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
540        write!(f, "{}", self.as_str())
541    }
542}
543
544impl DispatchError {
545    /// Returns a string representation of the error.
546    #[inline]
547    fn as_str(&self) -> &'static str {
548        match self {
549            Self::InvalidSelector => "unable to decode selector",
550            Self::UnknownSelector => "encountered unknown selector",
551            Self::InvalidParameters => "unable to decode input",
552            Self::CouldNotReadInput => "could not read input",
553            Self::PaidUnpayableMessage => "paid an unpayable message",
554        }
555    }
556}
557
558impl From<DispatchError> for scale::Error {
559    #[inline]
560    fn from(error: DispatchError) -> Self {
561        Self::from(error.as_str())
562    }
563}
564
565/// Decodes an ink! dispatch input into a known selector and its expected parameters.
566///
567/// # Note
568///
569/// This trait is automatically implemented for ink! message and constructor decoders.
570///
571/// # Errors
572///
573/// Returns an error if any of the decode steps failed:
574///
575/// - `InvalidSelector`: The first four bytes could not properly decoded into the
576///   selector.
577/// - `UnknownSelector`: The decoded selector did not match any of the expected ones.
578/// - `InvalidParameters`: Failed to decoded the parameters for the selected dispatchable.
579///
580/// The other dispatch errors are handled by other structures usually.
581///
582/// # Usage
583///
584/// todo: previous doc test used a contract instance, it was in the `ink!` crate.
585pub trait DecodeDispatch: Sized {
586    /// todo: docs
587    fn decode_dispatch(input: &mut &[u8]) -> Result<Self, DispatchError>;
588}