iota_adapter_latest/
execution_mode.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use iota_types::{
6    error::ExecutionError, execution::ExecutionResult, transaction::Argument, transfer::Receiving,
7};
8use move_core_types::language_storage::TypeTag;
9
10use crate::{
11    execution_value::{RawValueType, Value},
12    type_resolver::TypeTagResolver,
13};
14
15pub type TransactionIndex = usize;
16
17pub trait ExecutionMode {
18    /// All updates to a Arguments used in that Command
19    type ArgumentUpdates;
20    /// the gathered results from batched executions
21    type ExecutionResults;
22
23    /// Controls the calling of arbitrary Move functions
24    fn allow_arbitrary_function_calls() -> bool;
25
26    /// Controls the ability to instantiate any Move function parameter with a
27    /// Pure call arg.  In other words, you can instantiate any struct or
28    /// object or other value with its BCS byte
29    fn allow_arbitrary_values() -> bool;
30
31    /// Do not perform conservation checks after execution.
32    fn skip_conservation_checks() -> bool;
33
34    /// If not set, the package ID should be calculated like an object and an
35    /// UpgradeCap is produced
36    fn packages_are_predefined() -> bool;
37
38    fn empty_arguments() -> Self::ArgumentUpdates;
39
40    fn empty_results() -> Self::ExecutionResults;
41
42    fn add_argument_update(
43        resolver: &impl TypeTagResolver,
44        acc: &mut Self::ArgumentUpdates,
45        arg: Argument,
46        _new_value: &Value,
47    ) -> Result<(), ExecutionError>;
48
49    fn finish_command(
50        resolver: &impl TypeTagResolver,
51        acc: &mut Self::ExecutionResults,
52        argument_updates: Self::ArgumentUpdates,
53        command_result: &[Value],
54    ) -> Result<(), ExecutionError>;
55
56    /// Whether to allow passing in `AuthContext` as an argument to Move
57    /// functions.
58    fn allow_auth_context() -> bool;
59}
60
61#[derive(Copy, Clone)]
62pub struct Normal;
63
64impl ExecutionMode for Normal {
65    type ArgumentUpdates = ();
66    type ExecutionResults = ();
67
68    fn allow_arbitrary_function_calls() -> bool {
69        false
70    }
71
72    fn allow_arbitrary_values() -> bool {
73        false
74    }
75
76    fn skip_conservation_checks() -> bool {
77        false
78    }
79
80    fn packages_are_predefined() -> bool {
81        false
82    }
83
84    fn empty_arguments() -> Self::ArgumentUpdates {}
85
86    fn empty_results() -> Self::ExecutionResults {}
87
88    fn add_argument_update(
89        _resolver: &impl TypeTagResolver,
90        _acc: &mut Self::ArgumentUpdates,
91        _arg: Argument,
92        _new_value: &Value,
93    ) -> Result<(), ExecutionError> {
94        Ok(())
95    }
96
97    fn finish_command(
98        _resolver: &impl TypeTagResolver,
99        _acc: &mut Self::ExecutionResults,
100        _argument_updates: Self::ArgumentUpdates,
101        _command_result: &[Value],
102    ) -> Result<(), ExecutionError> {
103        Ok(())
104    }
105
106    fn allow_auth_context() -> bool {
107        false
108    }
109}
110
111#[derive(Copy, Clone)]
112pub struct Genesis;
113
114impl ExecutionMode for Genesis {
115    type ArgumentUpdates = ();
116    type ExecutionResults = ();
117
118    fn allow_arbitrary_function_calls() -> bool {
119        true
120    }
121
122    fn allow_arbitrary_values() -> bool {
123        true
124    }
125
126    fn packages_are_predefined() -> bool {
127        true
128    }
129
130    fn skip_conservation_checks() -> bool {
131        false
132    }
133
134    fn empty_arguments() -> Self::ArgumentUpdates {}
135
136    fn empty_results() -> Self::ExecutionResults {}
137
138    fn add_argument_update(
139        _resolver: &impl TypeTagResolver,
140        _acc: &mut Self::ArgumentUpdates,
141        _arg: Argument,
142        _new_value: &Value,
143    ) -> Result<(), ExecutionError> {
144        Ok(())
145    }
146
147    fn finish_command(
148        _resolver: &impl TypeTagResolver,
149        _acc: &mut Self::ExecutionResults,
150        _argument_updates: Self::ArgumentUpdates,
151        _command_result: &[Value],
152    ) -> Result<(), ExecutionError> {
153        Ok(())
154    }
155
156    fn allow_auth_context() -> bool {
157        false
158    }
159}
160
161#[derive(Copy, Clone)]
162pub struct System;
163
164/// Execution mode for executing a system transaction, including the epoch
165/// change transaction and the consensus commit prologue. In this mode, we allow
166/// calls to any function bypassing visibility.
167impl ExecutionMode for System {
168    type ArgumentUpdates = ();
169    type ExecutionResults = ();
170
171    fn allow_arbitrary_function_calls() -> bool {
172        // allows bypassing visibility for system calls
173        true
174    }
175
176    fn allow_arbitrary_values() -> bool {
177        // For AuthenticatorStateUpdate, we need to be able to pass in a vector of
178        // JWKs, so we need to allow arbitrary values.
179        true
180    }
181
182    fn skip_conservation_checks() -> bool {
183        false
184    }
185
186    fn packages_are_predefined() -> bool {
187        true
188    }
189
190    fn empty_arguments() -> Self::ArgumentUpdates {}
191
192    fn empty_results() -> Self::ExecutionResults {}
193
194    fn add_argument_update(
195        _resolver: &impl TypeTagResolver,
196        _acc: &mut Self::ArgumentUpdates,
197        _arg: Argument,
198        _new_value: &Value,
199    ) -> Result<(), ExecutionError> {
200        Ok(())
201    }
202
203    fn finish_command(
204        _resolver: &impl TypeTagResolver,
205        _acc: &mut Self::ExecutionResults,
206        _argument_updates: Self::ArgumentUpdates,
207        _command_result: &[Value],
208    ) -> Result<(), ExecutionError> {
209        Ok(())
210    }
211
212    fn allow_auth_context() -> bool {
213        false
214    }
215}
216
217#[derive(Copy, Clone)]
218pub struct Authentication;
219
220impl ExecutionMode for Authentication {
221    type ArgumentUpdates = ();
222    type ExecutionResults = ();
223
224    fn allow_arbitrary_function_calls() -> bool {
225        false
226    }
227
228    fn allow_arbitrary_values() -> bool {
229        false
230    }
231
232    fn skip_conservation_checks() -> bool {
233        false
234    }
235
236    fn packages_are_predefined() -> bool {
237        false
238    }
239
240    fn empty_arguments() -> Self::ArgumentUpdates {}
241
242    fn empty_results() -> Self::ExecutionResults {}
243
244    fn add_argument_update(
245        _resolver: &impl TypeTagResolver,
246        _acc: &mut Self::ArgumentUpdates,
247        _arg: Argument,
248        _new_value: &Value,
249    ) -> Result<(), ExecutionError> {
250        Ok(())
251    }
252
253    fn finish_command(
254        _resolver: &impl TypeTagResolver,
255        _acc: &mut Self::ExecutionResults,
256        _argument_updates: Self::ArgumentUpdates,
257        _command_result: &[Value],
258    ) -> Result<(), ExecutionError> {
259        Ok(())
260    }
261
262    fn allow_auth_context() -> bool {
263        true
264    }
265}
266
267/// WARNING! Using this mode will bypass all normal checks around Move entry
268/// functions! This includes the various rules for function arguments, meaning
269/// any object can be created just from BCS bytes!
270pub struct DevInspect<const SKIP_ALL_CHECKS: bool>;
271
272impl<const SKIP_ALL_CHECKS: bool> ExecutionMode for DevInspect<SKIP_ALL_CHECKS> {
273    type ArgumentUpdates = Vec<(Argument, Vec<u8>, TypeTag)>;
274    type ExecutionResults = Vec<ExecutionResult>;
275
276    fn allow_arbitrary_function_calls() -> bool {
277        SKIP_ALL_CHECKS
278    }
279
280    fn allow_arbitrary_values() -> bool {
281        SKIP_ALL_CHECKS
282    }
283
284    fn skip_conservation_checks() -> bool {
285        SKIP_ALL_CHECKS
286    }
287
288    fn packages_are_predefined() -> bool {
289        false
290    }
291
292    fn empty_arguments() -> Self::ArgumentUpdates {
293        vec![]
294    }
295
296    fn empty_results() -> Self::ExecutionResults {
297        vec![]
298    }
299
300    fn add_argument_update(
301        resolver: &impl TypeTagResolver,
302        acc: &mut Self::ArgumentUpdates,
303        arg: Argument,
304        new_value: &Value,
305    ) -> Result<(), ExecutionError> {
306        let (bytes, type_tag) = value_to_bytes_and_tag(resolver, new_value)?;
307        acc.push((arg, bytes, type_tag));
308        Ok(())
309    }
310
311    fn finish_command(
312        resolver: &impl TypeTagResolver,
313        acc: &mut Self::ExecutionResults,
314        argument_updates: Self::ArgumentUpdates,
315        command_result: &[Value],
316    ) -> Result<(), ExecutionError> {
317        let command_bytes = command_result
318            .iter()
319            .map(|value| value_to_bytes_and_tag(resolver, value))
320            .collect::<Result<_, _>>()?;
321        acc.push((argument_updates, command_bytes));
322        Ok(())
323    }
324
325    fn allow_auth_context() -> bool {
326        false
327    }
328}
329
330fn value_to_bytes_and_tag(
331    resolver: &impl TypeTagResolver,
332    value: &Value,
333) -> Result<(Vec<u8>, TypeTag), ExecutionError> {
334    let (type_tag, bytes) = match value {
335        Value::Object(obj) => {
336            let tag = resolver.get_type_tag(&obj.type_)?;
337            let mut bytes = vec![];
338            obj.write_bcs_bytes(&mut bytes, None)?;
339            (tag, bytes)
340        }
341        Value::Raw(RawValueType::Any, bytes) => {
342            // this case shouldn't happen
343            (TypeTag::Vector(Box::new(TypeTag::U8)), bytes.clone())
344        }
345        Value::Raw(RawValueType::Loaded { ty, .. }, bytes) => {
346            let tag = resolver.get_type_tag(ty)?;
347            (tag, bytes.clone())
348        }
349        Value::Receiving(id, seqno, _) => (
350            Receiving::type_tag(),
351            Receiving::new(*id, *seqno).to_bcs_bytes(),
352        ),
353    };
354    Ok((bytes, type_tag))
355}