ink_env/call/
execution.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::marker::PhantomData;
16use ink_prelude::vec::Vec;
17use ink_primitives::{
18    SolEncode,
19    abi::{
20        AbiEncodeWith,
21        Ink,
22        SizedOutput,
23        Sol,
24    },
25    impl_all_tuples,
26    sol::SolTypeParamsEncode,
27};
28
29use super::{
30    selector::Selector,
31    utils::{
32        DecodeMessageResult,
33        ReturnType,
34    },
35};
36use crate::Environment;
37
38/// The input data and the expected return type of a contract execution.
39pub struct Execution<Args, Output, Abi> {
40    /// The input data for initiating a contract execution.
41    pub input: ExecutionInput<Args, Abi>,
42    /// The type of the expected return value of the contract execution.
43    pub output: ReturnType<Output>,
44}
45
46impl<Args, Output, Abi> Execution<Args, Output, Abi>
47where
48    Args: EncodeArgsWith<Abi>,
49    Output: DecodeMessageResult<Abi>,
50{
51    /// Construct a new contract execution with the given input data.
52    pub fn new(input: ExecutionInput<Args, Abi>) -> Self {
53        Self {
54            input,
55            output: ReturnType::default(),
56        }
57    }
58
59    /// Perform the execution of the contract with the given executor.
60    pub fn exec<I, E>(
61        self,
62        executor: &I,
63    ) -> Result<ink_primitives::MessageResult<Output>, I::Error>
64    where
65        E: Environment,
66        I: Executor<E>,
67    {
68        executor.exec(&self.input)
69    }
70}
71
72/// Implemented in different environments to perform contract execution.
73pub trait Executor<E: Environment> {
74    /// The type of the error that can be returned during execution.
75    type Error;
76    /// Perform the contract execution with the given input data, and return the result.
77    fn exec<Args, Output, Abi>(
78        &self,
79        input: &ExecutionInput<Args, Abi>,
80    ) -> Result<ink_primitives::MessageResult<Output>, Self::Error>
81    where
82        Args: EncodeArgsWith<Abi>,
83        Output: DecodeMessageResult<Abi>;
84}
85
86/// The input data for a smart contract execution.
87#[derive(Clone, Default, Debug)]
88pub struct ExecutionInput<Args, Abi> {
89    /// The selector (if any) for the smart contract execution.
90    selector: Option<Selector>,
91    /// The arguments of the smart contract execution.
92    args: Args,
93    _marker: PhantomData<Abi>,
94}
95
96impl<Abi> ExecutionInput<EmptyArgumentList<Abi>, Abi> {
97    /// Creates a new execution input with the given selector.
98    #[inline]
99    pub fn new(selector: Selector) -> Self {
100        Self {
101            selector: Some(selector),
102            args: ArgumentList::empty(),
103            _marker: Default::default(),
104        }
105    }
106}
107
108impl ExecutionInput<EmptyArgumentList<Sol>, Sol> {
109    /// Creates a new execution input with no selector.
110    ///
111    /// # Note
112    ///
113    /// Should only be used for Solidity ABI encoded constructors/instantiation.
114    #[inline]
115    pub fn no_selector() -> Self {
116        Self {
117            selector: None,
118            args: ArgumentList::empty(),
119            _marker: Default::default(),
120        }
121    }
122}
123
124impl<Abi> ExecutionInput<EmptyArgumentList<Abi>, Abi> {
125    /// Pushes an argument to the execution input.
126    #[inline]
127    pub fn push_arg<T>(
128        self,
129        arg: T,
130    ) -> ExecutionInput<ArgumentList<Argument<T>, EmptyArgumentList<Abi>, Abi>, Abi>
131    where
132        T: AbiEncodeWith<Abi>,
133    {
134        ExecutionInput {
135            selector: self.selector,
136            args: self.args.push_arg(arg),
137            _marker: Default::default(),
138        }
139    }
140}
141
142impl<Head, Rest, Abi> ExecutionInput<ArgumentList<Argument<Head>, Rest, Abi>, Abi> {
143    /// Pushes an argument to the execution input.
144    #[allow(clippy::type_complexity)]
145    #[inline]
146    pub fn push_arg<T>(
147        self,
148        arg: T,
149    ) -> ExecutionInput<ArgsList<T, ArgsList<Head, Rest, Abi>, Abi>, Abi>
150    where
151        T: AbiEncodeWith<Abi>,
152    {
153        ExecutionInput {
154            selector: self.selector,
155            args: self.args.push_arg(arg),
156            _marker: Default::default(),
157        }
158    }
159}
160
161impl<Args, Abi> ExecutionInput<Args, Abi> {
162    /// Modify the selector.
163    ///
164    /// Useful when using the [`ExecutionInput`] generated as part of the
165    /// `ContractRef`, but using a custom selector.
166    pub fn update_selector(&mut self, selector: Selector) {
167        self.selector = Some(selector);
168    }
169}
170
171impl<Args, Abi> ExecutionInput<Args, Abi>
172where
173    Args: EncodeArgsWith<Abi>,
174{
175    /// Encodes the execution input into a dynamic vector by combining the selector and
176    /// encoded arguments.
177    pub fn encode(&self) -> Vec<u8> {
178        let mut encoded = Vec::new();
179        if let Some(selector) = &self.selector {
180            encoded.extend(selector.to_bytes());
181        }
182        self.args.encode_to_vec(&mut encoded);
183        encoded
184    }
185
186    /// Encodes the execution input into a static buffer by combining the selector and
187    /// encoded arguments.
188    pub fn encode_to_slice(&self, buffer: &mut [u8]) -> usize {
189        let selector_len = if let Some(selector) = &self.selector {
190            let selector_bytes = selector.to_bytes();
191            let selector_len = selector_bytes.len();
192            buffer[..selector_len].copy_from_slice(&selector_bytes);
193            selector_len
194        } else {
195            0
196        };
197        let args_len = self.args.encode_to(&mut buffer[selector_len..]);
198        selector_len + args_len
199    }
200}
201
202/// An argument list.
203///
204/// This type is constructed mainly at compile type via type constructions
205/// to avoid having to allocate heap memory while constructing the encoded
206/// arguments. The potentially heap allocating encoding is done right at the end
207/// where we can leverage the static environmental buffer instead of allocating
208/// heap memory.
209#[derive(Clone, Default, Debug)]
210pub struct ArgumentList<Head, Rest, Abi> {
211    /// The first argument of the argument list.
212    head: Head,
213    /// All the rest arguments.
214    rest: Rest,
215    _marker: PhantomData<Abi>,
216}
217
218/// Minor simplification of an argument list with a head and rest.
219pub type ArgsList<Head, Rest, Abi> = ArgumentList<Argument<Head>, Rest, Abi>;
220
221/// A single argument and its reference to a known value.
222#[derive(Clone, Debug)]
223pub struct Argument<T> {
224    /// The reference to the known value.
225    ///
226    /// Used for the encoding at the end of the construction.
227    arg: T,
228}
229
230impl<T> Argument<T> {
231    /// Creates a new argument.
232    #[inline]
233    fn new(arg: T) -> Self {
234        Self { arg }
235    }
236}
237
238/// The end of an argument list.
239#[derive(Clone, Default, Debug)]
240pub struct ArgumentListEnd;
241
242/// An empty argument list.
243pub type EmptyArgumentList<Abi> = ArgumentList<ArgumentListEnd, ArgumentListEnd, Abi>;
244
245impl<Abi> EmptyArgumentList<Abi> {
246    /// Creates a new empty argument list.
247    #[inline]
248    pub fn empty() -> EmptyArgumentList<Abi> {
249        ArgumentList {
250            head: ArgumentListEnd,
251            rest: ArgumentListEnd,
252            _marker: Default::default(),
253        }
254    }
255
256    /// Pushes the first argument to the empty argument list.
257    #[inline]
258    pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
259    where
260        T: AbiEncodeWith<Abi>,
261    {
262        ArgumentList {
263            head: Argument::new(arg),
264            rest: self,
265            _marker: Default::default(),
266        }
267    }
268}
269
270impl<Head, Rest, Abi> ArgumentList<Argument<Head>, Rest, Abi> {
271    /// Pushes another argument to the argument list.
272    #[inline]
273    pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
274    where
275        T: AbiEncodeWith<Abi>,
276    {
277        ArgumentList {
278            head: Argument::new(arg),
279            rest: self,
280            _marker: Default::default(),
281        }
282    }
283}
284
285impl<T> scale::Encode for Argument<T>
286where
287    T: scale::Encode,
288{
289    #[inline]
290    fn size_hint(&self) -> usize {
291        <T as scale::Encode>::size_hint(&self.arg)
292    }
293
294    #[inline]
295    fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
296        <T as scale::Encode>::encode_to(&self.arg, output)
297    }
298}
299
300impl scale::Encode for EmptyArgumentList<Ink> {
301    #[inline]
302    fn size_hint(&self) -> usize {
303        0
304    }
305
306    #[inline]
307    fn encode_to<O: scale::Output + ?Sized>(&self, _output: &mut O) {}
308}
309
310impl<Head, Rest> scale::Encode for ArgumentList<Argument<Head>, Rest, Ink>
311where
312    Head: scale::Encode,
313    Rest: scale::Encode,
314{
315    #[inline]
316    fn size_hint(&self) -> usize {
317        scale::Encode::size_hint(&self.head)
318            .checked_add(scale::Encode::size_hint(&self.rest))
319            .expect("unable to checked_add")
320    }
321
322    #[inline]
323    fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
324        // We reverse the order of encoding because we build up the list of
325        // arguments in reverse order, too. This way we encode the arguments
326        // in the same order in which they have been pushed to the argument list
327        // while the argument list itself organizes them in reverse order.
328        scale::Encode::encode_to(&self.rest, output);
329        scale::Encode::encode_to(&self.head, output);
330    }
331}
332
333impl<Args> scale::Encode for ExecutionInput<Args, Ink>
334where
335    Args: scale::Encode,
336{
337    #[inline]
338    fn size_hint(&self) -> usize {
339        let selector_size = match &self.selector {
340            None => 0,
341            Some(_) => scale::Encode::size_hint(&self.selector),
342        };
343        selector_size
344            .checked_add(scale::Encode::size_hint(&self.args))
345            .expect("unable to checked_add")
346    }
347
348    #[inline]
349    fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
350        if let Some(selector) = &self.selector {
351            scale::Encode::encode_to(selector, output);
352        }
353        scale::Encode::encode_to(&self.args, output);
354    }
355}
356
357impl<'a, T> SolEncode<'a> for Argument<T>
358where
359    T: SolEncode<'a>,
360{
361    type SolType = <T as SolEncode<'a>>::SolType;
362
363    fn to_sol_type(&'a self) -> Self::SolType {
364        self.arg.to_sol_type()
365    }
366}
367
368/// Trait for encoding an arguments list as per the specified ABI.
369pub trait EncodeArgsWith<Abi> {
370    /// Encodes the data into a new vector.
371    fn encode(&self) -> Vec<u8>;
372
373    /// Encodes the data into a fixed-size buffer, returning the number of bytes written.
374    fn encode_to(&self, buffer: &mut [u8]) -> usize;
375
376    /// Encodes the data into a dynamically resizing vector.
377    fn encode_to_vec(&self, buffer: &mut Vec<u8>);
378}
379
380impl<T: scale::Encode> EncodeArgsWith<Ink> for T {
381    fn encode(&self) -> Vec<u8> {
382        scale::Encode::encode(self)
383    }
384
385    fn encode_to(&self, buffer: &mut [u8]) -> usize {
386        let mut sized_output = SizedOutput::from(buffer);
387        scale::Encode::encode_to(self, &mut sized_output);
388        sized_output.len()
389    }
390
391    fn encode_to_vec(&self, buffer: &mut Vec<u8>) {
392        scale::Encode::encode_to(self, buffer);
393    }
394}
395
396impl EncodeArgsWith<Sol> for EmptyArgumentList<Sol> {
397    fn encode(&self) -> Vec<u8> {
398        Vec::new()
399    }
400
401    fn encode_to(&self, _buffer: &mut [u8]) -> usize {
402        0
403    }
404
405    fn encode_to_vec(&self, _buffer: &mut Vec<u8>) {}
406}
407
408impl<Head, Rest> EncodeArgsWith<Sol> for ArgumentList<Argument<Head>, Rest, Sol>
409where
410    for<'a> Self: ArgsListNestedTuple<'a>,
411    for<'a> <Self as ArgsListNestedTuple<'a>>::OutputType: ArgsListFlatTuple,
412    for<'a> <<Self as ArgsListNestedTuple<'a>>::OutputType as ArgsListFlatTuple>::OutputType:
413        SolTypeParamsEncode,
414{
415    fn encode(&self) -> Vec<u8> {
416        SolTypeParamsEncode::encode(&self.nested_tuple().flat_tuple())
417    }
418
419    fn encode_to(&self, buffer: &mut [u8]) -> usize {
420        SolTypeParamsEncode::encode_to(&self.nested_tuple().flat_tuple(), buffer)
421    }
422
423    fn encode_to_vec(&self, buffer: &mut Vec<u8>) {
424        buffer.extend(self.encode());
425    }
426}
427
428/// Converts `ArgumentList` into a nested tuple representation.
429trait ArgsListNestedTuple<'a> {
430    type OutputType;
431
432    fn nested_tuple(&'a self) -> Self::OutputType;
433}
434
435impl ArgsListNestedTuple<'_> for EmptyArgumentList<Sol> {
436    type OutputType = ();
437
438    fn nested_tuple(&self) {}
439}
440
441impl<'a, Head, Rest> ArgsListNestedTuple<'a> for ArgumentList<Argument<Head>, Rest, Sol>
442where
443    Rest: ArgsListNestedTuple<'a>,
444    Head: SolEncode<'a>,
445{
446    type OutputType = (Rest::OutputType, <Head as SolEncode<'a>>::SolType);
447
448    fn nested_tuple(&'a self) -> Self::OutputType {
449        (self.rest.nested_tuple(), self.head.arg.to_sol_type())
450    }
451}
452
453/// Converts an `ArgumentList` nested tuple into a flat tuple.
454trait ArgsListFlatTuple {
455    type OutputType;
456
457    fn flat_tuple(self) -> Self::OutputType;
458}
459
460impl ArgsListFlatTuple for () {
461    type OutputType = ();
462
463    fn flat_tuple(self) {}
464}
465
466// Converts from `A, B, C` to `((((), A), B), C)`
467macro_rules! args_list_nested_tuple {
468    // Initialize.
469    ($($ty:ident),* $(,)?) => {
470        args_list_nested_tuple!(($($ty),*) @out: ())
471    };
472    // Process.
473    (($Head:ident $(, $Rest:ident)*) @out: $Out:tt) => {
474        args_list_nested_tuple!(($($Rest),*) @out: ($Out, $Head))
475    };
476    // Finalize.
477    (() @out: $Out:tt) => { $Out };
478}
479
480macro_rules! impl_flat_tuple {
481    ($( $ty: ident ),*) => {
482        impl<$( $ty ),*> ArgsListFlatTuple for args_list_nested_tuple!($( $ty ),*) {
483            type OutputType = ( $( $ty, )* );
484
485            fn flat_tuple(self) -> Self::OutputType {
486                #[allow(bad_style)]
487                let args_list_nested_tuple!($( $ty ),*) = self;
488                ( $( $ty, )* )
489            }
490        }
491    };
492}
493
494impl_all_tuples!(@nonempty impl_flat_tuple);
495
496#[cfg(test)]
497mod tests {
498    use super::*;
499
500    #[test]
501    fn empty_exec_input_works() {
502        let selector = Selector::new([0x01, 0x02, 0x03, 0x04]);
503        let exec_input = ExecutionInput::new(selector);
504        let encoded = scale::Encode::encode(&exec_input);
505        assert!(!encoded.is_empty());
506        let decoded = <Selector as scale::Decode>::decode(&mut &encoded[..]).unwrap();
507        assert_eq!(decoded, selector);
508    }
509
510    #[test]
511    fn empty_args_works() {
512        let empty_list = ArgumentList::empty();
513        let encoded = scale::Encode::encode(&empty_list);
514        assert_eq!(encoded, <Vec<u8>>::new());
515    }
516
517    #[test]
518    fn single_argument_works() {
519        let empty_list = ArgumentList::empty().push_arg(&1i32);
520        let encoded = scale::Encode::encode(&empty_list);
521        assert!(!encoded.is_empty());
522        let decoded = <i32 as scale::Decode>::decode(&mut &encoded[..]).unwrap();
523        assert_eq!(decoded, 1i32);
524    }
525
526    #[test]
527    fn multiple_arguments_works() {
528        let empty_list = ArgumentList::empty()
529            .push_arg(&42i32)
530            .push_arg(&true)
531            .push_arg(&[0x66u8; 4]);
532        let encoded = scale::Encode::encode(&empty_list);
533        assert!(!encoded.is_empty());
534        let decoded =
535            <(i32, bool, [u8; 4]) as scale::Decode>::decode(&mut &encoded[..]).unwrap();
536        assert_eq!(decoded, (42i32, true, [0x66; 4]));
537    }
538
539    #[test]
540    fn sol_empty_args_works() {
541        let empty_list = ArgumentList::empty();
542        let encoded = EncodeArgsWith::<Sol>::encode(&empty_list);
543        assert_eq!(encoded, Vec::<u8>::new());
544    }
545
546    #[test]
547    fn sol_single_argument_works() {
548        let args_list = ArgumentList::empty().push_arg(&1i32);
549        let encoded = EncodeArgsWith::<Sol>::encode(&args_list);
550        assert!(!encoded.is_empty());
551        let (decoded,) =
552            ink_primitives::sol::decode_sequence::<(i32,)>(&encoded).unwrap();
553        assert_eq!(decoded, 1i32);
554    }
555
556    #[test]
557    fn sol_encoding_arguments_works() {
558        let args_list = EmptyArgumentList::<Sol>::empty()
559            .push_arg(100u8)
560            .push_arg(vec![1, 2, 3, 4])
561            .push_arg(String::from("Hello, world!"))
562            .push_arg(true);
563        let encoded_args_list = EncodeArgsWith::<Sol>::encode(&args_list);
564
565        let args_tuple = (100u8, vec![1, 2, 3, 4], String::from("Hello, world!"), true);
566        let encoded_args_tuple = ink_primitives::sol::encode_sequence(&args_tuple);
567
568        assert_eq!(encoded_args_list, encoded_args_tuple);
569    }
570}