ink_codegen/generator/
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 core::iter;
16
17use derive_more::From;
18use ir::{
19    Callable,
20    CallableWithSelector,
21    Constructor,
22    HexLiteral as _,
23    Message,
24};
25use proc_macro2::{
26    Ident,
27    TokenStream as TokenStream2,
28};
29use quote::{
30    format_ident,
31    quote,
32    quote_spanned,
33};
34use syn::{
35    spanned::Spanned as _,
36    LitInt,
37};
38
39#[cfg(any(ink_abi = "sol", ink_abi = "all"))]
40use crate::generator::sol;
41use crate::{
42    generator,
43    GenerateCode,
44};
45
46/// A message to be dispatched.
47/// Contains its callable and calculated unique id
48pub struct MessageDispatchable<'a> {
49    message: CallableWithSelector<'a, Message>,
50    id: TokenStream2,
51}
52
53/// A constructor to be dispatched.
54/// Contains its callable and calculated unique id
55pub struct ConstructorDispatchable<'a> {
56    constructor: CallableWithSelector<'a, Constructor>,
57    id: LitInt,
58}
59
60/// Generates code for the message and constructor dispatcher.
61///
62/// This code efficiently selects the dispatched ink! constructor or message
63/// by inspecting the first four bytes (selector) of the given input bytes.
64///
65/// As this happens on every contract execution this code must be highly optimized.
66/// For that purpose a so-called dispatch enum is being generated that has a
67/// specialized `scale::Decode` implementation taking the first four bytes of
68/// the input stream in order to identify the enum variant that it is going to
69/// produce out of the rest of the input buffer.
70///
71/// The rest of the input buffer is then automatically decoded directly into the
72/// expected input types of the respective ink! constructor or message.
73#[derive(From)]
74pub struct Dispatch<'a> {
75    contract: &'a ir::Contract,
76}
77impl_as_ref_for_generator!(Dispatch);
78
79impl GenerateCode for Dispatch<'_> {
80    fn generate_code(&self) -> TokenStream2 {
81        let messages = self.compose_messages_with_ids();
82        let constructors = self.compose_constructors_with_ids();
83
84        let contract_dispatchable_constructor_infos =
85            self.generate_dispatchable_constructor_infos();
86        let contract_dispatchable_messages_infos =
87            self.generate_dispatchable_message_infos();
88        let constructor_decoder_type =
89            self.generate_constructor_decoder_type(&constructors);
90        let message_decoder_type = self.generate_message_decoder_type(&messages);
91        let entry_points = self.generate_entry_points(&constructors, &messages);
92
93        #[cfg(not(any(ink_abi = "sol", ink_abi = "all")))]
94        let solidity_call_info = quote!();
95
96        #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
97        let solidity_call_info = self.generate_solidity_call_info();
98
99        quote! {
100            #contract_dispatchable_constructor_infos
101            #contract_dispatchable_messages_infos
102            #constructor_decoder_type
103            #message_decoder_type
104
105            #solidity_call_info
106
107            #[cfg(not(any(test, feature = "std", feature = "ink-as-dependency")))]
108            mod __do_not_access__ {
109                use super::*;
110                #entry_points
111            }
112        }
113    }
114}
115
116impl Dispatch<'_> {
117    /// Returns the index of the ink! message which has a wildcard selector, if existent.
118    fn query_wildcard_message(&self) -> Option<usize> {
119        self.contract
120            .module()
121            .impls()
122            .flat_map(|item_impl| item_impl.iter_messages())
123            .position(|item| item.has_wildcard_selector())
124    }
125
126    /// Returns the index of the ink! constructor which has a wildcard selector, if
127    /// existent.
128    fn query_wildcard_constructor(&self) -> Option<usize> {
129        self.contract
130            .module()
131            .impls()
132            .flat_map(|item_impl| item_impl.iter_constructors())
133            .position(|item| item.has_wildcard_selector())
134    }
135
136    /// Puts messages and their calculated selector ids in a single data structure
137    ///
138    /// See [`MessageDispatchable`]
139    fn compose_messages_with_ids(&self) -> Vec<MessageDispatchable> {
140        #[cfg(not(ink_abi = "sol"))]
141        let storage_ident = self.contract.module().storage().ident();
142        self.contract
143            .module()
144            .impls()
145            .flat_map(|item_impl| {
146                iter::repeat(item_impl.trait_path()).zip(item_impl.iter_messages())
147            })
148            .flat_map(|(trait_path, message)| {
149                let mut message_dispatchables = Vec::new();
150
151                #[cfg(not(ink_abi = "sol"))]
152                {
153                    let span = message.span();
154                    let id = if let Some(trait_path) = trait_path {
155                        let local_id = message.local_id().hex_padded_suffixed();
156                        quote_spanned!(span=>
157                            {
158                                ::core::primitive::u32::from_be_bytes(
159                                    <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
160                                        as #trait_path>::__ink_TraitInfo
161                                        as ::ink::reflect::TraitMessageInfo<#local_id>>::SELECTOR
162                                )
163                            }
164                        )
165                    } else {
166                        let id = message
167                            .composed_selector()
168                            .into_be_u32()
169                            .hex_padded_suffixed();
170                        quote_spanned!(span=>
171                            #id
172                        )
173                    };
174                    message_dispatchables.push(MessageDispatchable { message, id });
175                }
176
177                #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
178                {
179                    let id = sol::utils::selector_id(&message);
180                    message_dispatchables.push(MessageDispatchable { message, id });
181                    let _ = trait_path; // removes unused warning.
182                }
183
184                message_dispatchables
185            })
186            .collect::<Vec<_>>()
187    }
188
189    /// Puts constructors and their calculated selector ids in a single data structure
190    ///
191    /// See [`ConstructorDispatchable`]
192    fn compose_constructors_with_ids(&self) -> Vec<ConstructorDispatchable> {
193        self.contract
194            .module()
195            .impls()
196            .flat_map(|item_impl| item_impl.iter_constructors())
197            .map(|constructor| {
198                let id = constructor
199                    .composed_selector()
200                    .into_be_u32()
201                    .hex_padded_suffixed();
202                ConstructorDispatchable { constructor, id }
203            })
204            .collect::<Vec<_>>()
205    }
206
207    /// Generate code for the [`ink::DispatchableConstructorInfo`] trait implementations.
208    ///
209    /// These trait implementations store relevant dispatch information for every
210    /// dispatchable ink! constructor of the ink! smart contract.
211    fn generate_dispatchable_constructor_infos(&self) -> TokenStream2 {
212        let span = self.contract.module().storage().span();
213        let storage_ident = self.contract.module().storage().ident();
214        let constructor_infos = self
215            .contract
216            .module()
217            .impls()
218            .flat_map(|item_impl| item_impl.iter_constructors())
219            .map(|constructor| {
220                let constructor_span = constructor.span();
221                let constructor_ident = constructor.ident();
222                let payable = constructor.is_payable();
223                let selector_id = constructor.composed_selector().into_be_u32().hex_padded_suffixed();
224                let selector_bytes = constructor.composed_selector().hex_lits();
225                let cfg_attrs = constructor.get_cfg_attrs(constructor_span);
226                let output_type = constructor.output().map(quote::ToTokens::to_token_stream)
227                    .unwrap_or_else(|| quote! { () });
228                let input_bindings = generator::input_bindings(constructor.inputs());
229                let input_tuple_type = generator::input_types_tuple(constructor.inputs());
230                let input_tuple_bindings = generator::input_bindings_tuple(constructor.inputs());
231                let constructor_return_type = quote_spanned!(constructor_span=>
232                    <::ink::reflect::ConstructorOutputValue<#output_type>
233                        as ::ink::reflect::ConstructorOutput<#storage_ident>>
234                );
235                quote_spanned!(constructor_span =>
236                    #( #cfg_attrs )*
237                    impl ::ink::reflect::DispatchableConstructorInfo<#selector_id> for #storage_ident {
238                        type Input = #input_tuple_type;
239                        type Output = #output_type;
240                        type Storage = #storage_ident;
241                        type Error = #constructor_return_type::Error;
242                        const IS_RESULT: ::core::primitive::bool = #constructor_return_type::IS_RESULT;
243
244                        const CALLABLE: fn(Self::Input) -> Self::Output = |#input_tuple_bindings| {
245                            #storage_ident::#constructor_ident(#( #input_bindings ),* )
246                        };
247                        const PAYABLE: ::core::primitive::bool = #payable;
248                        const SELECTOR: [::core::primitive::u8; 4usize] = [ #( #selector_bytes ),* ];
249                        const LABEL: &'static ::core::primitive::str = ::core::stringify!(#constructor_ident);
250                    }
251                )
252            });
253        quote_spanned!(span=>
254            #( #constructor_infos )*
255        )
256    }
257
258    /// Generate code for the [`ink::DispatchableMessageInfo`] trait implementations.
259    ///
260    /// These trait implementations store relevant dispatch information for every
261    /// dispatchable ink! message of the ink! smart contract.
262    #[allow(clippy::vec_init_then_push)] // due to ABI conditional push to `message_infos` vec.
263    fn generate_dispatchable_message_infos(&self) -> TokenStream2 {
264        let span = self.contract.module().storage().span();
265
266        let inherent_message_infos = self
267            .contract
268            .module()
269            .impls()
270            .filter(|item_impl| item_impl.trait_path().is_none())
271            .flat_map(|item_impl| item_impl.iter_messages())
272            .flat_map(|message| {
273                let mut message_infos = Vec::new();
274
275                #[cfg(not(ink_abi = "sol"))]
276                message_infos.push(self.dispatchable_inherent_message_infos(&message));
277
278                #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
279                message_infos.push(self.solidity_message_info(&message, None));
280
281                message_infos
282            });
283        let trait_message_infos = self
284            .contract
285            .module()
286            .impls()
287            .filter_map(|item_impl| {
288                item_impl
289                    .trait_path()
290                    .map(|trait_path| {
291                        let trait_ident = item_impl.trait_ident().expect(
292                            "must have an ink! trait identifier if it is an ink! trait implementation"
293                        );
294                        iter::repeat((trait_ident, trait_path)).zip(item_impl.iter_messages())
295                    })
296            })
297            .flatten()
298            .flat_map(|((trait_ident, trait_path), message)| {
299                let mut message_infos = Vec::new();
300
301                #[cfg(not(ink_abi = "sol"))]
302                message_infos.push(self.dispatchable_trait_message_infos(&message, trait_ident, trait_path));
303
304                // NOTE: Solidity selectors are always computed from the call signature and input types.
305                #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
306                message_infos.push(self.solidity_message_info(&message, Some((trait_ident, trait_path))));
307
308                message_infos
309            });
310        quote_spanned!(span=>
311            #( #inherent_message_infos )*
312            #( #trait_message_infos )*
313        )
314    }
315
316    /// Generate code for the [`ink::DispatchableMessageInfo`] trait implementations.
317    ///
318    /// These trait implementations store relevant dispatch information for every
319    /// inherent dispatchable ink! message of the ink! smart contract.
320    #[cfg(not(ink_abi = "sol"))]
321    fn dispatchable_inherent_message_infos(
322        &self,
323        message: &CallableWithSelector<Message>,
324    ) -> TokenStream2 {
325        let storage_ident = self.contract.module().storage().ident();
326
327        let message_span = message.span();
328        let message_ident = message.ident();
329        let payable = message.is_payable();
330        let mutates = message.receiver().is_ref_mut();
331
332        let cfg_attrs = message.get_cfg_attrs(message_span);
333        let output_tuple_type = message
334            .output()
335            .map(quote::ToTokens::to_token_stream)
336            .unwrap_or_else(|| quote! { () });
337        let input_bindings = generator::input_bindings(message.inputs());
338        let input_tuple_type = generator::input_types_tuple(message.inputs());
339        let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
340
341        let selector_id = message
342            .composed_selector()
343            .into_be_u32()
344            .hex_padded_suffixed();
345        let selector_bytes = message.composed_selector().hex_lits();
346
347        #[cfg(feature = "std")]
348        let return_type = quote! { () };
349        #[cfg(not(feature = "std"))]
350        let return_type = quote! { ! };
351
352        quote_spanned!(message_span=>
353            #( #cfg_attrs )*
354            impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
355                type Input = #input_tuple_type;
356                type Output = #output_tuple_type;
357                type Storage = #storage_ident;
358
359                const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
360                    |storage, #input_tuple_bindings| {
361                        #storage_ident::#message_ident( storage #( , #input_bindings )* )
362                    };
363                const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
364                    |input| {
365                        <Self::Input as ::ink::scale::Decode>::decode(input)
366                            .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
367                    };
368                const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
369                    |flags, output| {
370                        ::ink::env::return_value::<::ink::MessageResult::<Self::Output>>(
371                            flags,
372                            // Currently no `LangError`s are raised at this level of the
373                            // dispatch logic so `Ok` is always returned to the caller.
374                            &::ink::MessageResult::Ok(output),
375                        )
376                    };
377                const SELECTOR: [::core::primitive::u8; 4usize] = [ #( #selector_bytes ),* ];
378                const PAYABLE: ::core::primitive::bool = #payable;
379                const MUTATES: ::core::primitive::bool = #mutates;
380                const LABEL: &'static ::core::primitive::str = ::core::stringify!(#message_ident);
381                const ENCODING: ::ink::reflect::Encoding = ::ink::reflect::Encoding::Scale;
382            }
383        )
384    }
385
386    /// Generate code for the [`ink::DispatchableMessageInfo`] trait implementations.
387    ///
388    /// These trait implementations store relevant dispatch information for every
389    /// trait implementation dispatchable ink! message of the ink! smart contract.
390    #[cfg(not(ink_abi = "sol"))]
391    fn dispatchable_trait_message_infos(
392        &self,
393        message: &CallableWithSelector<Message>,
394        trait_ident: &Ident,
395        trait_path: &syn::Path,
396    ) -> TokenStream2 {
397        let storage_ident = self.contract.module().storage().ident();
398
399        let message_span = message.span();
400        let message_ident = message.ident();
401        let mutates = message.receiver().is_ref_mut();
402        let local_id = message.local_id().hex_padded_suffixed();
403        let payable = quote! {{
404            <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
405                as #trait_path>::__ink_TraitInfo
406                as ::ink::reflect::TraitMessageInfo<#local_id>>::PAYABLE
407        }};
408        let selector = quote! {{
409            <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
410                as #trait_path>::__ink_TraitInfo
411                as ::ink::reflect::TraitMessageInfo<#local_id>>::SELECTOR
412        }};
413        let selector_id = quote! {{
414            ::core::primitive::u32::from_be_bytes(#selector)
415        }};
416        let output_tuple_type = message
417            .output()
418            .map(quote::ToTokens::to_token_stream)
419            .unwrap_or_else(|| quote! { () });
420        let input_bindings = generator::input_bindings(message.inputs());
421        let input_tuple_type = generator::input_types_tuple(message.inputs());
422        let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
423        let label = format!("{trait_ident}::{message_ident}");
424        let cfg_attrs = message.get_cfg_attrs(message_span);
425
426        #[cfg(feature = "std")]
427        let return_type = quote! { () };
428        #[cfg(not(feature = "std"))]
429        let return_type = quote! { ! };
430
431        quote_spanned!(message_span=>
432            #( #cfg_attrs )*
433            impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
434                type Input = #input_tuple_type;
435                type Output = #output_tuple_type;
436                type Storage = #storage_ident;
437
438                const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
439                    |storage, #input_tuple_bindings| {
440                        <#storage_ident as #trait_path>::#message_ident( storage #( , #input_bindings )* )
441                    };
442                const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
443                    |input| {
444                        <Self::Input as ::ink::scale::Decode>::decode(input)
445                            .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
446                    };
447                const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
448                    |flags, output| {
449                        ::ink::env::return_value::<::ink::MessageResult::<Self::Output>>(
450                            flags,
451                            // Currently no `LangError`s are raised at this level of the
452                            // dispatch logic so `Ok` is always returned to the caller.
453                            &::ink::MessageResult::Ok(output),
454                        )
455                    };
456                const SELECTOR: [::core::primitive::u8; 4usize] = #selector;
457                const PAYABLE: ::core::primitive::bool = #payable;
458                const MUTATES: ::core::primitive::bool = #mutates;
459                const LABEL: &'static ::core::primitive::str = #label;
460                const ENCODING: ::ink::reflect::Encoding = ::ink::reflect::Encoding::Scale;
461            }
462        )
463    }
464
465    /// Generate code for [`ink::DispatchableMessageInfo`] trait implementations for
466    /// Solidity ABI compatible calls.
467    #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
468    fn solidity_message_info(
469        &self,
470        message: &CallableWithSelector<Message>,
471        trait_info: Option<(&Ident, &syn::Path)>,
472    ) -> TokenStream2 {
473        let storage_ident = self.contract.module().storage().ident();
474        let message_span = message.span();
475        let message_ident = message.ident();
476        let payable = message.is_payable();
477        let mutates = message.receiver().is_ref_mut();
478
479        let cfg_attrs = message.get_cfg_attrs(message_span);
480        let output_tuple_type = message
481            .output()
482            .map(quote::ToTokens::to_token_stream)
483            .unwrap_or_else(|| quote! { () });
484        let input_bindings = generator::input_bindings(message.inputs());
485        let input_tuple_type = generator::input_types_tuple(message.inputs());
486        let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
487
488        let selector_id = sol::utils::selector_id(message);
489        let selector_bytes = sol::utils::selector(message);
490
491        let (call_prefix, label) = match trait_info {
492            None => {
493                (
494                    quote! {
495                        #storage_ident
496                    },
497                    message_ident.to_string(),
498                )
499            }
500            Some((trait_ident, trait_path)) => {
501                (
502                    quote! {
503                        <#storage_ident as #trait_path>
504                    },
505                    format!("{trait_ident}::{message_ident}"),
506                )
507            }
508        };
509
510        #[cfg(feature = "std")]
511        let return_type = quote! { () };
512        #[cfg(not(feature = "std"))]
513        let return_type = quote! { ! };
514
515        quote_spanned!(message_span=>
516            #( #cfg_attrs )*
517            impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
518                type Input = #input_tuple_type;
519                type Output = #output_tuple_type;
520                type Storage = #storage_ident;
521
522                const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
523                    |storage, #input_tuple_bindings| {
524                        #call_prefix::#message_ident( storage #( , #input_bindings )* )
525                    };
526                const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
527                    |input| {
528                        <Self::Input as ::ink::SolDecode>::decode(input)
529                            .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
530                    };
531                const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
532                    |flags, output| {
533                        ::ink::env::return_value_solidity::<Self::Output>(
534                            flags,
535                            &output,
536                        )
537                    };
538                const SELECTOR: [::core::primitive::u8; 4usize] = #selector_bytes;
539                const PAYABLE: ::core::primitive::bool = #payable;
540                const MUTATES: ::core::primitive::bool = #mutates;
541                const LABEL: &'static ::core::primitive::str = #label;
542                const ENCODING: ::ink::reflect::Encoding = ::ink::reflect::Encoding::Solidity;
543            }
544        )
545    }
546
547    /// Generates code for the entry points of the root ink! smart contract.
548    ///
549    /// This generates the `deploy` and `call` functions with which the smart
550    /// contract runtime mainly interacts with the ink! smart contract.
551    fn generate_entry_points(
552        &self,
553        constructors: &[ConstructorDispatchable],
554        messages: &[MessageDispatchable],
555    ) -> TokenStream2 {
556        let span = self.contract.module().storage().span();
557        let storage_ident = self.contract.module().storage().ident();
558        let any_constructor_accept_payment =
559            self.any_constructor_accepts_payment(constructors);
560        let any_message_accepts_payment = self.any_message_accepts_payment(messages);
561
562        let fn_call: syn::ItemFn = syn::parse_quote! {
563            #[cfg(target_arch = "riscv64")]
564            #[::ink::polkavm_export(abi = ::ink::polkavm_derive::default_abi)]
565            pub extern "C" fn call() {
566                internal_call()
567            }
568        };
569        let fn_deploy: syn::ItemFn = syn::parse_quote! {
570            #[cfg(target_arch = "riscv64")]
571            #[::ink::polkavm_export(abi = ::ink::polkavm_derive::default_abi)]
572            pub extern "C" fn deploy() {
573                internal_deploy()
574            }
575        };
576        quote_spanned!(span=>
577            #[allow(dead_code)] // clippy throws a false positive otherwise
578            #[allow(clippy::nonminimal_bool)]
579            #[cfg(target_arch = "riscv64")]
580            fn internal_deploy() {
581                if !#any_constructor_accept_payment {
582                    ::ink::codegen::deny_payment()
583                        .unwrap_or_else(|error| ::core::panic!("{}", error))
584                }
585
586                let dispatchable = match ::ink::env::decode_input::<
587                    <#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type,
588                >() {
589                    ::core::result::Result::Ok(decoded_dispatchable) => {
590                        decoded_dispatchable
591                    }
592                    ::core::result::Result::Err(_decoding_error) => {
593                        let error = ::ink::ConstructorResult::Err(::ink::LangError::CouldNotReadInput);
594
595                        // At this point we're unable to set the `Ok` variant to be the "real"
596                        // constructor output since we were unable to figure out what the caller wanted
597                        // to dispatch in the first place, so we set it to `()`.
598                        //
599                        // This is okay since we're going to only be encoding the `Err` variant
600                        // into the output buffer anyway.
601                        ::ink::env::return_value::<::ink::ConstructorResult<()>>(
602                            ::ink::env::ReturnFlags::REVERT,
603                            &error,
604                        );
605                    }
606                };
607
608                <<#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type
609                    as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable)
610                .unwrap_or_else(|error| {
611                    ::core::panic!("dispatching ink! constructor failed: {}", error)
612                })
613            }
614
615            #[allow(dead_code)] // clippy throws a false positive otherwise
616            #[allow(clippy::nonminimal_bool)]
617            #[cfg(target_arch = "riscv64")]
618            fn internal_call() {
619                if !#any_message_accepts_payment {
620                    ::ink::codegen::deny_payment()
621                        .unwrap_or_else(|error| ::core::panic!("{}", error))
622                }
623
624                let dispatchable = match ::ink::env::decode_input::<
625                    <#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type,
626                >() {
627                    ::core::result::Result::Ok(decoded_dispatchable) => {
628                        decoded_dispatchable
629                    }
630                    ::core::result::Result::Err(_decoding_error) => {
631                        let error = ::ink::MessageResult::Err(::ink::LangError::CouldNotReadInput);
632
633                        // At this point we're unable to set the `Ok` variant to be the "real"
634                        // message output since we were unable to figure out what the caller wanted
635                        // to dispatch in the first place, so we set it to `()`.
636                        //
637                        // This is okay since we're going to only be encoding the `Err` variant
638                        // into the output buffer anyway.
639                        ::ink::env::return_value::<::ink::MessageResult<()>>(
640                            ::ink::env::ReturnFlags::REVERT,
641                            &error,
642                        );
643                    }
644                };
645
646                <<#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type
647                    as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable)
648                .unwrap_or_else(|error| {
649                    ::core::panic!("dispatching ink! message failed: {}", error)
650                })
651            }
652
653            #fn_call
654
655            #fn_deploy
656        )
657    }
658
659    /// Generates code for the ink! constructor decoder type of the ink! smart contract.
660    ///
661    /// This type can be used in order to decode the input bytes received by a call to
662    /// `deploy` into one of the available dispatchable ink! constructors and their
663    /// arguments.
664    fn generate_constructor_decoder_type(
665        &self,
666        constructors: &[ConstructorDispatchable],
667    ) -> TokenStream2 {
668        /// Expands into the token sequence to represent the
669        /// input type of the ink! constructor at the given index.
670        fn expand_constructor_input(
671            span: proc_macro2::Span,
672            storage_ident: &syn::Ident,
673            constructor_id: LitInt,
674        ) -> TokenStream2 {
675            quote_spanned!(span=>
676                <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #constructor_id >>::Input
677            )
678        }
679
680        /// Returns the n-th ink! constructor identifier for the decoder type.
681        fn constructor_variant_ident(n: usize) -> syn::Ident {
682            quote::format_ident!("Constructor{}", n)
683        }
684
685        let span = self.contract.module().storage().span();
686        let storage_ident = self.contract.module().storage().ident();
687        let constructors_variants =
688            constructors.iter().enumerate().map(|(index, item)| {
689                let constructor_span = item.constructor.span();
690                let constructor_ident = constructor_variant_ident(index);
691                let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
692                let constructor_input = expand_constructor_input(
693                    constructor_span,
694                    storage_ident,
695                    item.id.clone(),
696                );
697                quote_spanned!(constructor_span=>
698                    #( #cfg_attrs )*
699                    #constructor_ident(#constructor_input)
700                )
701            });
702
703        let constructor_selector=
704            constructors.iter().enumerate().map(|(index, item)| {
705            let constructor_span = item.constructor.span();
706            let const_ident = format_ident!("CONSTRUCTOR_{}", index);
707            let id = item.id.clone();
708            let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
709            quote_spanned!(span=>
710                #( #cfg_attrs )*
711                const #const_ident: [::core::primitive::u8; 4usize] = <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::SELECTOR;
712            )
713        });
714
715        let constructor_match = constructors.iter().enumerate().map(|(index, item)| {
716            let constructor_span = item.constructor.span();
717            let constructor_ident = constructor_variant_ident(index);
718            let const_ident = format_ident!("CONSTRUCTOR_{}", index);
719            let constructor_input = expand_constructor_input(
720                constructor_span,
721                storage_ident,
722                item.id.clone(),
723            );
724            let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
725            quote_spanned!(constructor_span=>
726                #( #cfg_attrs )*
727                #const_ident => {
728                    ::core::result::Result::Ok(Self::#constructor_ident(
729                        <#constructor_input as ::ink::scale::Decode>::decode(input)
730                            .map_err(|_| ::ink::env::DispatchError::InvalidParameters)?
731                    ))
732                }
733            )
734        });
735        let possibly_wildcard_selector_constructor = match self
736            .query_wildcard_constructor()
737        {
738            Some(wildcard_index) => {
739                let item = &constructors[wildcard_index];
740                let constructor_span = item.constructor.span();
741                let constructor_ident = constructor_variant_ident(wildcard_index);
742                let constructor_input = expand_constructor_input(
743                    constructor_span,
744                    storage_ident,
745                    item.id.clone(),
746                );
747                quote! {
748                    ::core::result::Result::Ok(Self::#constructor_ident(
749                        <#constructor_input as ::ink::scale::Decode>::decode(input)
750                            .map_err(|_| ::ink::env::DispatchError::InvalidParameters)?
751                    ))
752                }
753            }
754            None => {
755                quote! {
756                    ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
757                }
758            }
759        };
760
761        let constructor_execute = constructors.iter().enumerate().map(|(index, item)| {
762            let constructor_span = item.constructor.span();
763            let constructor_ident = constructor_variant_ident(index);
764            let id = item.id.clone();
765            let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
766            let constructor_callable = quote_spanned!(constructor_span=>
767                <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::CALLABLE
768            );
769            let constructor_output = quote_spanned!(constructor_span=>
770                <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::Output
771            );
772            let deny_payment = quote_spanned!(constructor_span=>
773                !<#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::PAYABLE
774            );
775            let constructor_value = quote_spanned!(constructor_span=>
776                <::ink::reflect::ConstructorOutputValue<#constructor_output>
777                    as ::ink::reflect::ConstructorOutput::<#storage_ident>>
778            );
779
780            let constructor_accept_payment_assignment =
781                self.any_constructor_accepts_payment(constructors);
782
783            quote_spanned!(constructor_span=>
784                #( #cfg_attrs )*
785                Self::#constructor_ident(input) => {
786                    if #constructor_accept_payment_assignment && #deny_payment {
787                        ::ink::codegen::deny_payment()?;
788                    }
789
790                    let result: #constructor_output = #constructor_callable(input);
791                    let output_value = ::ink::reflect::ConstructorOutputValue::new(result);
792                    let output_result = #constructor_value::as_result(&output_value);
793
794                    if let ::core::result::Result::Ok(contract) = output_result.as_ref() {
795                        ::ink::env::set_contract_storage::<::ink::primitives::Key, #storage_ident>(
796                            &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY,
797                            contract,
798                        );
799                    }
800
801                    // NOTE: we can't use an if/else expression here
802                    // It fails inside quote_spanned! macro.
803                    // See https://github.com/rust-lang/rust-clippy/issues/6249
804                    let mut flag = ::ink::env::ReturnFlags::empty();
805                    if output_result.is_err() {
806                        flag = ::ink::env::ReturnFlags::REVERT;
807                    }
808
809                    ::ink::env::return_value::<
810                        ::ink::ConstructorResult<
811                            ::core::result::Result<(), &#constructor_value::Error>
812                        >,
813                    >(
814                        flag,
815                        // Currently no `LangError`s are raised at this level of the
816                        // dispatch logic so `Ok` is always returned to the caller.
817                        &::ink::ConstructorResult::Ok(output_result.map(|_| ())),
818                    );
819
820                    #[cfg(feature = "std")]
821                    return ::core::result::Result::Ok(());
822
823                    #[cfg(not(feature = "std"))]
824                    #[cfg_attr(not(feature = "std"), allow(unreachable_code))]
825                    {
826                        ::core::unreachable!("either `return_value` or the `return` before will already have returned");
827                    }
828                }
829            )
830        });
831        quote_spanned!(span=>
832            const _: () = {
833                #[allow(non_camel_case_types)]
834                pub enum __ink_ConstructorDecoder {
835                    #( #constructors_variants ),*
836                }
837
838                impl ::ink::env::DecodeDispatch for __ink_ConstructorDecoder {
839                    fn decode_dispatch(input: &mut &[::core::primitive::u8])
840                        -> ::core::result::Result<Self, ::ink::env::DispatchError> {
841                        #(
842                            #constructor_selector
843                        )*
844                        match <[::core::primitive::u8; 4usize] as ::ink::scale::Decode>::decode(input)
845                            .map_err(|_| ::ink::env::DispatchError::InvalidSelector)?
846                        {
847                            #( #constructor_match , )*
848                            _invalid => #possibly_wildcard_selector_constructor
849                        }
850                    }
851                }
852
853                impl ::ink::reflect::ExecuteDispatchable for __ink_ConstructorDecoder {
854                    #[allow(clippy::nonminimal_bool, dead_code)]
855                    fn execute_dispatchable(self) -> ::core::result::Result<(), ::ink::env::DispatchError> {
856                        match self {
857                            #( #constructor_execute ),*
858                        }
859                    }
860                }
861
862                impl ::ink::reflect::ContractConstructorDecoder for #storage_ident {
863                    type Type = __ink_ConstructorDecoder;
864                }
865            };
866        )
867    }
868
869    /// Generates code for the ink! message decoder type of the ink! smart contract.
870    ///
871    /// This type can be used in order to decode the input bytes received by a call to
872    /// `call` into one of the available dispatchable ink! messages and their
873    /// arguments.
874    fn generate_message_decoder_type(
875        &self,
876        messages: &[MessageDispatchable],
877    ) -> TokenStream2 {
878        /// Expands into the token sequence to represent the
879        /// input type of the ink! message at the given index.
880        fn expand_message_input(
881            span: proc_macro2::Span,
882            storage_ident: &syn::Ident,
883            message_id: TokenStream2,
884        ) -> TokenStream2 {
885            quote_spanned!(span=>
886                <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #message_id >>::Input
887            )
888        }
889
890        /// Returns the n-th ink! message identifier for the decoder type.
891        fn message_variant_ident(n: usize) -> syn::Ident {
892            quote::format_ident!("Message{}", n)
893        }
894
895        let span = self.contract.module().storage().span();
896        let storage_ident = self.contract.module().storage().ident();
897        let message_variants = messages.iter().enumerate().map(|(index, item)| {
898            let message_span = item.message.span();
899            let message_ident = message_variant_ident(index);
900            let cfg_attrs = item.message.get_cfg_attrs(message_span);
901            let message_input =
902                expand_message_input(message_span, storage_ident, item.id.clone());
903            quote_spanned!(message_span=>
904                #( #cfg_attrs )*
905                #message_ident(#message_input)
906            )
907        });
908
909        let message_selector = messages
910            .iter()
911            .enumerate()
912            .map(|(index, item)|  {
913                let message_span = item.message.span();
914                let const_ident = format_ident!("MESSAGE_{}", index);
915                let cfg_attrs = item.message.get_cfg_attrs(message_span);
916                let id = item.id.clone();
917                quote_spanned!(span=>
918                    #( #cfg_attrs )*
919                    const #const_ident: [::core::primitive::u8; 4usize] = <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::SELECTOR;
920                )
921        });
922
923        let message_match =  messages
924            .iter()
925            .enumerate()
926            .map(|(index, item)| {
927                let message_ident = message_variant_ident(index);
928                let const_ident = format_ident!("MESSAGE_{}", index);
929                let message_span = item.message.span();
930                let cfg_attrs = item.message.get_cfg_attrs(message_span);
931                let id = item.id.clone();
932                quote_spanned!(message_span=>
933                   #( #cfg_attrs )*
934                    #const_ident => {
935                        ::core::result::Result::Ok(Self::#message_ident(
936                            <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::DECODE(input)?
937                        ))
938                    }
939                )
940        });
941        let possibly_wildcard_selector_message = match self.query_wildcard_message() {
942            Some(wildcard_index) => {
943                let item = messages
944                    .get(wildcard_index)
945                    .expect("unable to get wildcard index");
946                let message_span = item.message.span();
947                let message_ident = message_variant_ident(wildcard_index);
948                let message_input =
949                    expand_message_input(message_span, storage_ident, item.id.clone());
950                quote! {
951                    ::core::result::Result::Ok(Self::#message_ident(
952                        <#message_input as ::ink::scale::Decode>::decode(input)
953                            .map_err(|_| ::ink::env::DispatchError::InvalidParameters)?
954                    ))
955                }
956            }
957            None => {
958                quote! {
959                    ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
960                }
961            }
962        };
963
964        let message_execute = messages
965            .iter()
966            .enumerate()
967            .map(|(index, item)| {
968                let message_span = item.message.span();
969                let message_ident = message_variant_ident(index);
970                let id = item.id.clone();
971                let cfg_attrs = item.message.get_cfg_attrs(message_span);
972                let message_callable = quote_spanned!(message_span=>
973                    <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::CALLABLE
974                );
975                let message_return = quote_spanned!(message_span=>
976                    <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::RETURN
977                );
978                let message_output = quote_spanned!(message_span=>
979                    <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::Output
980                );
981                let deny_payment = quote_spanned!(message_span=>
982                    !<#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::PAYABLE
983                );
984                let mutates_storage = quote_spanned!(message_span=>
985                    <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::MUTATES
986                );
987
988                let any_message_accepts_payment =
989                    self.any_message_accepts_payment(messages);
990
991                quote_spanned!(message_span=>
992                    #( #cfg_attrs )*
993                    Self::#message_ident(input) => {
994                        if #any_message_accepts_payment && #deny_payment {
995                            ::ink::codegen::deny_payment()?;
996                        }
997
998                        let result: #message_output = #message_callable(&mut contract, input);
999                        let is_reverted = ::ink::is_result_type!(#message_output)
1000                            && ::ink::is_result_err!(result);
1001
1002                        // NOTE: we can't use an if/else expression here
1003                        // It fails inside quote_spanned! macro.
1004                        // See https://github.com/rust-lang/rust-clippy/issues/6249
1005                        let mut flag = ::ink::env::ReturnFlags::REVERT;
1006
1007                        // no need to push back results: transaction gets reverted anyway
1008                        if !is_reverted {
1009                            flag = ::ink::env::ReturnFlags::empty();
1010                            push_contract(contract, #mutates_storage);
1011                        }
1012
1013                        #message_return(flag, result);
1014
1015                        #[cfg(feature = "std")]
1016                        return ::core::result::Result::Ok(());
1017
1018                        #[cfg(not(feature = "std"))]
1019                        #[cfg_attr(not(feature = "std"), allow(unreachable_code))]
1020                        {
1021                            ::core::unreachable!("either `return_value` or the `return` before will already have returned");
1022                        }
1023                    }
1024                )
1025        });
1026
1027        quote_spanned!(span=>
1028            const _: () = {
1029                #[allow(non_camel_case_types)]
1030                pub enum __ink_MessageDecoder {
1031                    #( #message_variants ),*
1032                }
1033
1034                impl ::ink::env::DecodeDispatch for __ink_MessageDecoder {
1035                    fn decode_dispatch(input: &mut &[::core::primitive::u8])
1036                        -> ::core::result::Result<Self, ::ink::env::DispatchError> {
1037                        #(
1038                            #message_selector
1039                        )*
1040                        match <[::core::primitive::u8; 4usize] as ::ink::scale::Decode>::decode(input)
1041                            .map_err(|_| ::ink::env::DispatchError::InvalidSelector)?
1042                        {
1043                            #( #message_match , )*
1044                            _invalid => #possibly_wildcard_selector_message
1045                        }
1046                    }
1047                }
1048
1049                fn push_contract(contract: ::core::mem::ManuallyDrop<#storage_ident>, mutates: bool) {
1050                    if mutates {
1051                        ::ink::env::set_contract_storage::<::ink::primitives::Key, #storage_ident>(
1052                            &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY,
1053                            &contract,
1054                        );
1055                    }
1056                }
1057
1058                impl ::ink::reflect::ExecuteDispatchable for __ink_MessageDecoder {
1059                    #[allow(clippy::nonminimal_bool, clippy::let_unit_value, dead_code)]
1060                    fn execute_dispatchable(
1061                        self
1062                    ) -> ::core::result::Result<(), ::ink::env::DispatchError> {
1063                        let key = <#storage_ident as ::ink::storage::traits::StorageKey>::KEY;
1064                        let mut contract: ::core::mem::ManuallyDrop<#storage_ident> =
1065                            ::core::mem::ManuallyDrop::new(
1066                                match ::ink::env::get_contract_storage(&key) {
1067                                    ::core::result::Result::Ok(::core::option::Option::Some(value)) => value,
1068                                    ::core::result::Result::Ok(::core::option::Option::None) => {
1069                                        ::core::panic!("storage entry was empty")
1070                                    },
1071                                    ::core::result::Result::Err(_) => {
1072                                        ::core::panic!("could not properly decode storage entry")
1073                                    },
1074                                }
1075                            );
1076
1077                        match self {
1078                            #( #message_execute ),*
1079                        }
1080                    }
1081                }
1082
1083                impl ::ink::reflect::ContractMessageDecoder for #storage_ident {
1084                    type Type = __ink_MessageDecoder;
1085                }
1086            };
1087        )
1088    }
1089
1090    /// Generates code to express if any dispatchable ink! message accepts payment.
1091    ///
1092    /// Generates code in the form of variable assignments
1093    /// which can be conditionally omitted
1094    /// in which case the default assignment `let message_{id} = false` exists.
1095    ///
1096    /// This information can be used to speed-up dispatch since denying of payment
1097    /// can be generalized to work before dispatch happens if none of the ink! messages
1098    /// accept payment anyways.
1099    fn any_message_accepts_payment(
1100        &self,
1101        messages: &[MessageDispatchable],
1102    ) -> TokenStream2 {
1103        let span = self.contract.module().storage().span();
1104        let storage_ident = self.contract.module().storage().ident();
1105        let message_is_payable =  messages
1106            .iter()
1107            .enumerate()
1108            .map(|(index, item)| {
1109            let message_span = item.message.span();
1110            let cfg_attrs = item.message.get_cfg_attrs(message_span);
1111            let id = item.id.clone();
1112            let ident = quote::format_ident!("message_{}", index);
1113            quote_spanned!(message_span=>
1114                {
1115                    let #ident = false;
1116                    #( #cfg_attrs )*
1117                    let #ident = <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::PAYABLE;
1118                    #ident
1119                }
1120            )
1121        });
1122        quote_spanned!(span=>
1123            {
1124                false #( || #message_is_payable )*
1125            }
1126        )
1127    }
1128
1129    /// Generates code to express if any dispatchable ink! constructor accepts payment.
1130    ///
1131    /// Generates code in the form of variable assignments
1132    /// which can be conditionally omitted
1133    /// in which case the default assignment `let constructor_{id} = false` exists.
1134    ///
1135    /// This information can be used to speed-up dispatch since denying of payment
1136    /// can be generalized to work before dispatch happens if none of the ink!
1137    /// constructors accept payment anyways.
1138    fn any_constructor_accepts_payment(
1139        &self,
1140        constructors: &[ConstructorDispatchable],
1141    ) -> TokenStream2 {
1142        let span = self.contract.module().storage().span();
1143        let storage_ident = self.contract.module().storage().ident();
1144        let constructor_is_payable = constructors.iter().enumerate().map(|(index, item)| {
1145            let constructor_span = item.constructor.span();
1146            let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
1147            let id = item.id.clone();
1148            let ident = quote::format_ident!("constructor_{}", index);
1149            quote_spanned!(constructor_span=>
1150                {
1151                    let #ident = false;
1152                    #( #cfg_attrs )*
1153                    let #ident = <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::PAYABLE;
1154                    #ident
1155                }
1156            )
1157        });
1158        quote_spanned!(span=>
1159            {
1160                false #( || #constructor_is_payable )*
1161            }
1162        )
1163    }
1164
1165    /// Generates code for Solidity call info types for dispatchable ink! messages.
1166    #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
1167    fn generate_solidity_call_info(&self) -> TokenStream2 {
1168        let span = self.contract.module().span();
1169        let call_tys = self
1170            .contract
1171            .module()
1172            .impls()
1173            .flat_map(|item_impl| item_impl.iter_messages())
1174            .map(|message| {
1175                let span = message.span();
1176                let ident = message.ident();
1177                let ident_str = ident.to_string();
1178                let call_type_ident = sol::utils::call_info_type_ident(&message);
1179                let signature = sol::utils::call_signature(ident_str, message.inputs());
1180
1181                quote_spanned!(span=>
1182                    pub struct #call_type_ident;
1183
1184                    const _: () = {
1185                        impl #call_type_ident {
1186                            pub const SIGNATURE: &'static ::core::primitive::str = #signature;
1187                            pub const SELECTOR: [::core::primitive::u8; 4usize] = ::ink::codegen::sol_selector_bytes(Self::SIGNATURE);
1188                            pub const SELECTOR_ID: ::core::primitive::u32 = ::core::primitive::u32::from_be_bytes(Self::SELECTOR);
1189                        }
1190                    };
1191                )
1192            });
1193        quote_spanned!(span=>
1194            #[allow(non_camel_case_types)]
1195            mod __ink_sol_interop__ {
1196                #[allow(unused)]
1197                use super::*;
1198
1199                #(#call_tys)*
1200            }
1201        )
1202    }
1203}