sui_adapter_latest/
execution_mode.rs

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