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 super::{
16    utils::ReturnType,
17    Selector,
18};
19use crate::{
20    call::utils::DecodeMessageResult,
21    Environment,
22};
23use core::marker::PhantomData;
24use ink_prelude::vec::Vec;
25use ink_primitives::{
26    reflect::{
27        AbiDecodeWith,
28        AbiEncodeWith,
29        ScaleEncoding,
30        SolEncoding,
31    },
32    SolEncode,
33};
34
35/// The input data and the expected return type of a contract execution.
36pub struct Execution<Args, Output, Abi> {
37    /// The input data for initiating a contract execution.
38    pub input: ExecutionInput<Args, Abi>,
39    /// The type of the expected return value of the contract execution.
40    pub output: ReturnType<Output>,
41}
42
43impl<Args, Output, Abi> Execution<Args, Output, Abi>
44where
45    Args: AbiEncodeWith<Abi>,
46    Output: AbiDecodeWith<Abi> + DecodeMessageResult<Abi>,
47{
48    /// Construct a new contract execution with the given input data.
49    pub fn new(input: ExecutionInput<Args, Abi>) -> Self {
50        Self {
51            input,
52            output: ReturnType::default(),
53        }
54    }
55
56    /// Perform the execution of the contract with the given executor.
57    pub fn exec<I, E>(
58        self,
59        executor: &I,
60    ) -> Result<ink_primitives::MessageResult<Output>, I::Error>
61    where
62        E: Environment,
63        I: Executor<E>,
64    {
65        executor.exec(&self.input)
66    }
67}
68
69/// Implemented in different environments to perform contract execution.
70pub trait Executor<E: Environment> {
71    /// The type of the error that can be returned during execution.
72    type Error;
73    /// Perform the contract execution with the given input data, and return the result.
74    fn exec<Args, Output, Abi>(
75        &self,
76        input: &ExecutionInput<Args, Abi>,
77    ) -> Result<ink_primitives::MessageResult<Output>, Self::Error>
78    where
79        Args: AbiEncodeWith<Abi>,
80        Output: AbiDecodeWith<Abi> + DecodeMessageResult<Abi>;
81}
82
83/// The input data for a smart contract execution.
84#[derive(Clone, Default, Debug)]
85pub struct ExecutionInput<Args, Abi> {
86    /// The selector for the smart contract execution.
87    selector: Selector,
88    /// The arguments of the smart contract execution.
89    args: Args,
90    _marker: PhantomData<Abi>,
91}
92
93impl<Abi> ExecutionInput<EmptyArgumentList<Abi>, Abi> {
94    /// Creates a new execution input with the given selector.
95    #[inline]
96    pub fn new(selector: Selector) -> Self {
97        Self {
98            selector,
99            args: ArgumentList::empty(),
100            _marker: Default::default(),
101        }
102    }
103
104    /// Pushes an argument to the execution input.
105    #[inline]
106    pub fn push_arg<T>(
107        self,
108        arg: T,
109    ) -> ExecutionInput<ArgumentList<Argument<T>, EmptyArgumentList<Abi>, Abi>, Abi>
110    where
111        T: AbiEncodeWith<Abi>,
112    {
113        ExecutionInput {
114            selector: self.selector,
115            args: self.args.push_arg(arg),
116            _marker: Default::default(),
117        }
118    }
119}
120
121impl<Head, Rest, Abi> ExecutionInput<ArgumentList<Argument<Head>, Rest, Abi>, Abi> {
122    /// Pushes an argument to the execution input.
123    #[allow(clippy::type_complexity)]
124    #[inline]
125    pub fn push_arg<T>(
126        self,
127        arg: T,
128    ) -> ExecutionInput<ArgsList<T, ArgsList<Head, Rest, Abi>, Abi>, Abi>
129    where
130        T: AbiEncodeWith<Abi>,
131    {
132        ExecutionInput {
133            selector: self.selector,
134            args: self.args.push_arg(arg),
135            _marker: Default::default(),
136        }
137    }
138}
139
140impl<Args, Abi> ExecutionInput<Args, Abi> {
141    /// Modify the selector.
142    ///
143    /// Useful when using the [`ExecutionInput`] generated as part of the
144    /// `ContractRef`, but using a custom selector.
145    pub fn update_selector(&mut self, selector: Selector) {
146        self.selector = selector;
147    }
148}
149
150impl<Args, Abi> ExecutionInput<Args, Abi>
151where
152    Args: AbiEncodeWith<Abi>,
153{
154    /// Encodes the execution input into a dynamic vector by combining the selector and
155    /// encoded arguments.
156    pub fn encode(&self) -> Vec<u8> {
157        let mut encoded = Vec::new();
158        encoded.extend(self.selector.to_bytes());
159        self.args.encode_to_vec(&mut encoded);
160        encoded
161    }
162
163    /// Encodes the execution input into a static buffer by combining the selector and
164    /// encoded arguments.
165    pub fn encode_to_slice(&self, buffer: &mut [u8]) -> usize {
166        let selector_bytes = self.selector.to_bytes();
167        let selector_len = selector_bytes.len();
168
169        buffer[..selector_len].copy_from_slice(&selector_bytes);
170        let args_len = self.args.encode_to_slice(&mut buffer[selector_len..]);
171        selector_len + args_len
172    }
173}
174
175/// An argument list.
176///
177/// This type is constructed mainly at compile type via type constructions
178/// to avoid having to allocate heap memory while constructing the encoded
179/// arguments. The potentially heap allocating encoding is done right at the end
180/// where we can leverage the static environmental buffer instead of allocating
181/// heap memory.
182#[derive(Clone, Default, Debug)]
183pub struct ArgumentList<Head, Rest, Abi> {
184    /// The first argument of the argument list.
185    head: Head,
186    /// All the rest arguments.
187    rest: Rest,
188    _marker: PhantomData<Abi>,
189}
190
191/// Minor simplification of an argument list with a head and rest.
192pub type ArgsList<Head, Rest, Abi> = ArgumentList<Argument<Head>, Rest, Abi>;
193
194/// A single argument and its reference to a known value.
195#[derive(Clone, Debug)]
196pub struct Argument<T> {
197    /// The reference to the known value.
198    ///
199    /// Used for the encoding at the end of the construction.
200    arg: T,
201}
202
203impl<T> Argument<T> {
204    /// Creates a new argument.
205    #[inline]
206    fn new(arg: T) -> Self {
207        Self { arg }
208    }
209}
210
211/// The end of an argument list.
212#[derive(Clone, Default, Debug)]
213pub struct ArgumentListEnd;
214
215/// An empty argument list.
216pub type EmptyArgumentList<Abi> = ArgumentList<ArgumentListEnd, ArgumentListEnd, Abi>;
217
218impl<Abi> EmptyArgumentList<Abi> {
219    /// Creates a new empty argument list.
220    #[inline]
221    pub fn empty() -> EmptyArgumentList<Abi> {
222        ArgumentList {
223            head: ArgumentListEnd,
224            rest: ArgumentListEnd,
225            _marker: Default::default(),
226        }
227    }
228
229    /// Pushes the first argument to the empty argument list.
230    #[inline]
231    pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
232    where
233        T: AbiEncodeWith<Abi>,
234    {
235        ArgumentList {
236            head: Argument::new(arg),
237            rest: self,
238            _marker: Default::default(),
239        }
240    }
241}
242
243impl<Head, Rest, Abi> ArgumentList<Argument<Head>, Rest, Abi> {
244    /// Pushes another argument to the argument list.
245    #[inline]
246    pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
247    where
248        T: AbiEncodeWith<Abi>,
249    {
250        ArgumentList {
251            head: Argument::new(arg),
252            rest: self,
253            _marker: Default::default(),
254        }
255    }
256}
257
258impl<T> scale::Encode for Argument<T>
259where
260    T: scale::Encode,
261{
262    #[inline]
263    fn size_hint(&self) -> usize {
264        <T as scale::Encode>::size_hint(&self.arg)
265    }
266
267    #[inline]
268    fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
269        <T as scale::Encode>::encode_to(&self.arg, output)
270    }
271}
272
273impl scale::Encode for EmptyArgumentList<ScaleEncoding> {
274    #[inline]
275    fn size_hint(&self) -> usize {
276        0
277    }
278
279    #[inline]
280    fn encode_to<O: scale::Output + ?Sized>(&self, _output: &mut O) {}
281}
282
283impl<Head, Rest> scale::Encode for ArgumentList<Argument<Head>, Rest, ScaleEncoding>
284where
285    Head: scale::Encode,
286    Rest: scale::Encode,
287{
288    #[inline]
289    fn size_hint(&self) -> usize {
290        scale::Encode::size_hint(&self.head)
291            .checked_add(scale::Encode::size_hint(&self.rest))
292            .expect("unable to checked_add")
293    }
294
295    #[inline]
296    fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
297        // We reverse the order of encoding because we build up the list of
298        // arguments in reverse order, too. This way we encode the arguments
299        // in the same order in which they have been pushed to the argument list
300        // while the argument list itself organizes them in reverse order.
301        scale::Encode::encode_to(&self.rest, output);
302        scale::Encode::encode_to(&self.head, output);
303    }
304}
305
306impl<Args> scale::Encode for ExecutionInput<Args, ScaleEncoding>
307where
308    Args: scale::Encode,
309{
310    #[inline]
311    fn size_hint(&self) -> usize {
312        scale::Encode::size_hint(&self.selector)
313            .checked_add(scale::Encode::size_hint(&self.args))
314            .expect("unable to checked_add")
315    }
316
317    #[inline]
318    fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
319        scale::Encode::encode_to(&self.selector, output);
320        scale::Encode::encode_to(&self.args, output);
321    }
322}
323
324impl<'a, T> SolEncode<'a> for Argument<T>
325where
326    T: SolEncode<'a>,
327{
328    type SolType = <T as SolEncode<'a>>::SolType;
329
330    fn to_sol_type(&'a self) -> Self::SolType {
331        self.arg.to_sol_type()
332    }
333}
334
335impl SolEncode<'_> for EmptyArgumentList<SolEncoding> {
336    type SolType = ();
337
338    fn encode(&self) -> Vec<u8> {
339        Vec::new()
340    }
341
342    // NOTE: Not actually used for encoding because of `encode` override above.
343    fn to_sol_type(&self) {}
344}
345
346impl<'a, Head, Rest> SolEncode<'a> for ArgumentList<Argument<Head>, Rest, SolEncoding>
347where
348    Head: SolEncode<'a>,
349    Rest: SolEncode<'a>,
350{
351    type SolType = (Rest::SolType, Head::SolType);
352
353    fn encode(&'a self) -> Vec<u8> {
354        let mut encoded = Vec::new();
355        encoded.extend(Rest::encode(&self.rest));
356        encoded.extend(Head::encode(&self.head.arg));
357        encoded
358    }
359
360    fn to_sol_type(&'a self) -> Self::SolType {
361        // NOTE: Not actually used for encoding because of `encode` override above.
362        (self.rest.to_sol_type(), self.head.arg.to_sol_type())
363    }
364}
365
366#[cfg(test)]
367mod tests {
368    use super::*;
369
370    #[test]
371    fn empty_exec_input_works() {
372        let selector = Selector::new([0x01, 0x02, 0x03, 0x04]);
373        let exec_input = ExecutionInput::new(selector);
374        let encoded = scale::Encode::encode(&exec_input);
375        assert!(!encoded.is_empty());
376        let decoded = <Selector as scale::Decode>::decode(&mut &encoded[..]).unwrap();
377        assert_eq!(decoded, selector);
378    }
379
380    #[test]
381    fn empty_args_works() {
382        let empty_list = ArgumentList::empty();
383        let encoded = scale::Encode::encode(&empty_list);
384        assert_eq!(encoded, <Vec<u8>>::new());
385    }
386
387    #[test]
388    fn single_argument_works() {
389        let empty_list = ArgumentList::empty().push_arg(&1i32);
390        let encoded = scale::Encode::encode(&empty_list);
391        assert!(!encoded.is_empty());
392        let decoded = <i32 as scale::Decode>::decode(&mut &encoded[..]).unwrap();
393        assert_eq!(decoded, 1i32);
394    }
395
396    #[test]
397    fn multiple_arguments_works() {
398        let empty_list = ArgumentList::empty()
399            .push_arg(&42i32)
400            .push_arg(&true)
401            .push_arg(&[0x66u8; 4]);
402        let encoded = scale::Encode::encode(&empty_list);
403        assert!(!encoded.is_empty());
404        let decoded =
405            <(i32, bool, [u8; 4]) as scale::Decode>::decode(&mut &encoded[..]).unwrap();
406        assert_eq!(decoded, (42i32, true, [0x66; 4]));
407    }
408}