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 alloy_sol_types::{
24    private::SolTypeValue,
25    SolType,
26    SolValue,
27    Word,
28};
29use core::marker::PhantomData;
30use ink_prelude::vec::Vec;
31use ink_primitives::reflect::{
32    AbiDecodeWith,
33    AbiEncodeWith,
34    ScaleEncoding,
35    SolEncoding,
36};
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: AbiEncodeWith<Abi>,
49    Output: AbiDecodeWith<Abi> + 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: AbiEncodeWith<Abi>,
83        Output: AbiDecodeWith<Abi> + 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 for the smart contract execution.
90    selector: 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,
102            args: ArgumentList::empty(),
103            _marker: Default::default(),
104        }
105    }
106
107    /// Pushes an argument to the execution input.
108    #[inline]
109    pub fn push_arg<T>(
110        self,
111        arg: T,
112    ) -> ExecutionInput<ArgumentList<Argument<T>, EmptyArgumentList<Abi>, Abi>, Abi>
113    where
114        T: AbiEncodeWith<Abi>,
115    {
116        ExecutionInput {
117            selector: self.selector,
118            args: self.args.push_arg(arg),
119            _marker: Default::default(),
120        }
121    }
122}
123
124impl<Head, Rest, Abi> ExecutionInput<ArgumentList<Argument<Head>, Rest, Abi>, Abi> {
125    /// Pushes an argument to the execution input.
126    #[allow(clippy::type_complexity)]
127    #[inline]
128    pub fn push_arg<T>(
129        self,
130        arg: T,
131    ) -> ExecutionInput<ArgsList<T, ArgsList<Head, Rest, Abi>, Abi>, Abi>
132    where
133        T: AbiEncodeWith<Abi>,
134    {
135        ExecutionInput {
136            selector: self.selector,
137            args: self.args.push_arg(arg),
138            _marker: Default::default(),
139        }
140    }
141}
142
143impl<Args, Abi> ExecutionInput<Args, Abi> {
144    /// Modify the selector.
145    ///
146    /// Useful when using the [`ExecutionInput`] generated as part of the
147    /// `ContractRef`, but using a custom selector.
148    pub fn update_selector(&mut self, selector: Selector) {
149        self.selector = selector;
150    }
151}
152
153impl<Args, Abi> ExecutionInput<Args, Abi>
154where
155    Args: AbiEncodeWith<Abi>,
156{
157    /// Encodes the execution input into a dynamic vector by combining the selector and
158    /// encoded arguments.
159    pub fn encode(&self) -> Vec<u8> {
160        let mut encoded = Vec::new();
161        encoded.extend(self.selector.to_bytes());
162        self.args.encode_to_vec(&mut encoded);
163        encoded
164    }
165
166    /// Encodes the execution input into a static buffer by combining the selector and
167    /// encoded arguments.
168    pub fn encode_to_slice(&self, buffer: &mut [u8]) -> usize {
169        let selector_bytes = self.selector.to_bytes();
170        let selector_len = selector_bytes.len();
171
172        buffer[..selector_len].copy_from_slice(&selector_bytes);
173        let args_len = self.args.encode_to_slice(&mut buffer[selector_len..]);
174        selector_len + args_len
175    }
176}
177
178/// An argument list.
179///
180/// This type is constructed mainly at compile type via type constructions
181/// to avoid having to allocate heap memory while constructing the encoded
182/// arguments. The potentially heap allocating encoding is done right at the end
183/// where we can leverage the static environmental buffer instead of allocating
184/// heap memory.
185#[derive(Clone, Default, Debug)]
186pub struct ArgumentList<Head, Rest, Abi> {
187    /// The first argument of the argument list.
188    head: Head,
189    /// All the rest arguments.
190    rest: Rest,
191    _marker: PhantomData<Abi>,
192}
193
194/// Minor simplification of an argument list with a head and rest.
195pub type ArgsList<Head, Rest, Abi> = ArgumentList<Argument<Head>, Rest, Abi>;
196
197/// A single argument and its reference to a known value.
198#[derive(Clone, Debug)]
199pub struct Argument<T> {
200    /// The reference to the known value.
201    ///
202    /// Used for the encoding at the end of the construction.
203    arg: T,
204}
205
206impl<T> Argument<T> {
207    /// Creates a new argument.
208    #[inline]
209    fn new(arg: T) -> Self {
210        Self { arg }
211    }
212}
213
214/// The end of an argument list.
215#[derive(Clone, Default, Debug)]
216pub struct ArgumentListEnd;
217
218/// An empty argument list.
219pub type EmptyArgumentList<Abi> = ArgumentList<ArgumentListEnd, ArgumentListEnd, Abi>;
220
221impl<Abi> EmptyArgumentList<Abi> {
222    /// Creates a new empty argument list.
223    #[inline]
224    pub fn empty() -> EmptyArgumentList<Abi> {
225        ArgumentList {
226            head: ArgumentListEnd,
227            rest: ArgumentListEnd,
228            _marker: Default::default(),
229        }
230    }
231
232    /// Pushes the first argument to the empty argument list.
233    #[inline]
234    pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
235    where
236        T: AbiEncodeWith<Abi>,
237    {
238        ArgumentList {
239            head: Argument::new(arg),
240            rest: self,
241            _marker: Default::default(),
242        }
243    }
244}
245
246impl<Head, Rest, Abi> ArgumentList<Argument<Head>, Rest, Abi> {
247    /// Pushes another argument to the argument list.
248    #[inline]
249    pub fn push_arg<T>(self, arg: T) -> ArgumentList<Argument<T>, Self, Abi>
250    where
251        T: AbiEncodeWith<Abi>,
252    {
253        ArgumentList {
254            head: Argument::new(arg),
255            rest: self,
256            _marker: Default::default(),
257        }
258    }
259}
260
261impl<T> scale::Encode for Argument<T>
262where
263    T: scale::Encode,
264{
265    #[inline]
266    fn size_hint(&self) -> usize {
267        <T as scale::Encode>::size_hint(&self.arg)
268    }
269
270    #[inline]
271    fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
272        <T as scale::Encode>::encode_to(&self.arg, output)
273    }
274}
275
276impl scale::Encode for EmptyArgumentList<ScaleEncoding> {
277    #[inline]
278    fn size_hint(&self) -> usize {
279        0
280    }
281
282    #[inline]
283    fn encode_to<O: scale::Output + ?Sized>(&self, _output: &mut O) {}
284}
285
286impl<Head, Rest> scale::Encode for ArgumentList<Argument<Head>, Rest, ScaleEncoding>
287where
288    Head: scale::Encode,
289    Rest: scale::Encode,
290{
291    #[inline]
292    fn size_hint(&self) -> usize {
293        scale::Encode::size_hint(&self.head)
294            .checked_add(scale::Encode::size_hint(&self.rest))
295            .expect("unable to checked_add")
296    }
297
298    #[inline]
299    fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
300        // We reverse the order of encoding because we build up the list of
301        // arguments in reverse order, too. This way we encode the arguments
302        // in the same order in which they have been pushed to the argument list
303        // while the argument list itself organizes them in reverse order.
304        scale::Encode::encode_to(&self.rest, output);
305        scale::Encode::encode_to(&self.head, output);
306    }
307}
308
309impl<Args> scale::Encode for ExecutionInput<Args, ScaleEncoding>
310where
311    Args: scale::Encode,
312{
313    #[inline]
314    fn size_hint(&self) -> usize {
315        scale::Encode::size_hint(&self.selector)
316            .checked_add(scale::Encode::size_hint(&self.args))
317            .expect("unable to checked_add")
318    }
319
320    #[inline]
321    fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
322        scale::Encode::encode_to(&self.selector, output);
323        scale::Encode::encode_to(&self.args, output);
324    }
325}
326
327impl<T> SolValue for Argument<T>
328where
329    T: SolValue,
330    Argument<T>: SolTypeValue<<T as SolValue>::SolType>,
331{
332    type SolType = <T as SolValue>::SolType;
333
334    fn abi_encode(&self) -> Vec<u8> {
335        <T as SolValue>::abi_encode(&self.arg)
336    }
337}
338
339impl SolTypeValue<()> for EmptyArgumentList<SolEncoding> {
340    fn stv_to_tokens(&self) -> <() as SolType>::Token<'_> {}
341
342    fn stv_abi_encode_packed_to(&self, _out: &mut Vec<u8>) {}
343
344    fn stv_eip712_data_word(&self) -> Word {
345        Word::from_slice(&[])
346    }
347}
348
349impl SolValue for EmptyArgumentList<SolEncoding> {
350    type SolType = ();
351
352    fn abi_encode(&self) -> Vec<u8> {
353        Vec::new()
354    }
355}
356
357impl<Head, Rest> SolTypeValue<(Rest::SolType, Head::SolType)>
358    for ArgumentList<Argument<Head>, Rest, SolEncoding>
359where
360    Head: SolValue,
361    Rest: SolValue,
362{
363    fn stv_to_tokens(
364        &self,
365    ) -> (
366        <Rest::SolType as SolType>::Token<'_>,
367        <Head::SolType as SolType>::Token<'_>,
368    ) {
369        (self.rest.stv_to_tokens(), self.head.arg.stv_to_tokens())
370    }
371
372    fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
373        self.rest.stv_abi_encode_packed_to(out);
374        self.head.arg.stv_abi_encode_packed_to(out);
375    }
376
377    fn stv_eip712_data_word(&self) -> Word {
378        todo!("Implement EIP-712 encoding for ArgumentList")
379    }
380}
381
382impl<Head, Rest> SolValue for ArgumentList<Argument<Head>, Rest, SolEncoding>
383where
384    Head: SolValue,
385    Rest: SolValue,
386{
387    type SolType = (Rest::SolType, Head::SolType);
388
389    fn abi_encode(&self) -> Vec<u8> {
390        let mut encoded = Vec::new();
391        encoded.extend(Rest::abi_encode(&self.rest));
392        encoded.extend(Head::abi_encode(&self.head.arg));
393        encoded
394    }
395}
396
397#[cfg(test)]
398mod tests {
399    use super::*;
400
401    #[test]
402    fn empty_exec_input_works() {
403        let selector = Selector::new([0x01, 0x02, 0x03, 0x04]);
404        let exec_input = ExecutionInput::new(selector);
405        let encoded = scale::Encode::encode(&exec_input);
406        assert!(!encoded.is_empty());
407        let decoded = <Selector as scale::Decode>::decode(&mut &encoded[..]).unwrap();
408        assert_eq!(decoded, selector);
409    }
410
411    #[test]
412    fn empty_args_works() {
413        let empty_list = ArgumentList::empty();
414        let encoded = scale::Encode::encode(&empty_list);
415        assert_eq!(encoded, <Vec<u8>>::new());
416    }
417
418    #[test]
419    fn single_argument_works() {
420        let empty_list = ArgumentList::empty().push_arg(&1i32);
421        let encoded = scale::Encode::encode(&empty_list);
422        assert!(!encoded.is_empty());
423        let decoded = <i32 as scale::Decode>::decode(&mut &encoded[..]).unwrap();
424        assert_eq!(decoded, 1i32);
425    }
426
427    #[test]
428    fn multiple_arguments_works() {
429        let empty_list = ArgumentList::empty()
430            .push_arg(&42i32)
431            .push_arg(&true)
432            .push_arg(&[0x66u8; 4]);
433        let encoded = scale::Encode::encode(&empty_list);
434        assert!(!encoded.is_empty());
435        let decoded =
436            <(i32, bool, [u8; 4]) as scale::Decode>::decode(&mut &encoded[..]).unwrap();
437        assert_eq!(decoded, (42i32, true, [0x66; 4]));
438    }
439}