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}