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