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}