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