sui_adapter_v0/
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
52#[derive(Copy, Clone)]
53pub struct Normal;
54
55impl ExecutionMode for Normal {
56    type ArgumentUpdates = ();
57    type ExecutionResults = ();
58
59    fn allow_arbitrary_function_calls() -> bool {
60        false
61    }
62
63    fn allow_arbitrary_values() -> bool {
64        false
65    }
66
67    fn skip_conservation_checks() -> bool {
68        false
69    }
70
71    fn packages_are_predefined() -> bool {
72        false
73    }
74
75    fn empty_arguments() -> Self::ArgumentUpdates {}
76
77    fn empty_results() -> Self::ExecutionResults {}
78
79    fn add_argument_update(
80        _resolver: &impl TypeTagResolver,
81        _acc: &mut Self::ArgumentUpdates,
82        _arg: Argument,
83        _new_value: &Value,
84    ) -> Result<(), ExecutionError> {
85        Ok(())
86    }
87
88    fn finish_command(
89        _resolver: &impl TypeTagResolver,
90        _acc: &mut Self::ExecutionResults,
91        _argument_updates: Self::ArgumentUpdates,
92        _command_result: &[Value],
93    ) -> Result<(), ExecutionError> {
94        Ok(())
95    }
96}
97
98#[derive(Copy, Clone)]
99pub struct Genesis;
100
101impl ExecutionMode for Genesis {
102    type ArgumentUpdates = ();
103    type ExecutionResults = ();
104
105    fn allow_arbitrary_function_calls() -> bool {
106        true
107    }
108
109    fn allow_arbitrary_values() -> bool {
110        true
111    }
112
113    fn packages_are_predefined() -> bool {
114        true
115    }
116
117    fn skip_conservation_checks() -> bool {
118        false
119    }
120
121    fn empty_arguments() -> Self::ArgumentUpdates {}
122
123    fn empty_results() -> Self::ExecutionResults {}
124
125    fn add_argument_update(
126        _resolver: &impl TypeTagResolver,
127        _acc: &mut Self::ArgumentUpdates,
128        _arg: Argument,
129        _new_value: &Value,
130    ) -> Result<(), ExecutionError> {
131        Ok(())
132    }
133
134    fn finish_command(
135        _resolver: &impl TypeTagResolver,
136        _acc: &mut Self::ExecutionResults,
137        _argument_updates: Self::ArgumentUpdates,
138        _command_result: &[Value],
139    ) -> Result<(), ExecutionError> {
140        Ok(())
141    }
142}
143
144#[derive(Copy, Clone)]
145pub struct System;
146
147/// Execution mode for executing a system transaction, including the epoch change
148/// transaction and the consensus commit prologue. In this mode, we allow calls to
149/// any function bypassing visibility.
150impl ExecutionMode for System {
151    type ArgumentUpdates = ();
152    type ExecutionResults = ();
153
154    fn allow_arbitrary_function_calls() -> bool {
155        // allows bypassing visibility for system calls
156        true
157    }
158
159    fn allow_arbitrary_values() -> bool {
160        // For AuthenticatorStateUpdate, we need to be able to pass in a vector of
161        // JWKs, so we need to allow arbitrary values.
162        true
163    }
164
165    fn skip_conservation_checks() -> bool {
166        false
167    }
168
169    fn packages_are_predefined() -> bool {
170        true
171    }
172
173    fn empty_arguments() -> Self::ArgumentUpdates {}
174
175    fn empty_results() -> Self::ExecutionResults {}
176
177    fn add_argument_update(
178        _resolver: &impl TypeTagResolver,
179        _acc: &mut Self::ArgumentUpdates,
180        _arg: Argument,
181        _new_value: &Value,
182    ) -> Result<(), ExecutionError> {
183        Ok(())
184    }
185
186    fn finish_command(
187        _resolver: &impl TypeTagResolver,
188        _acc: &mut Self::ExecutionResults,
189        _argument_updates: Self::ArgumentUpdates,
190        _command_result: &[Value],
191    ) -> Result<(), ExecutionError> {
192        Ok(())
193    }
194}
195
196/// WARNING! Using this mode will bypass all normal checks around Move entry functions! This
197/// includes the various rules for function arguments, meaning any object can be created just from
198/// BCS bytes!
199pub struct DevInspect<const SKIP_ALL_CHECKS: bool>;
200
201impl<const SKIP_ALL_CHECKS: bool> ExecutionMode for DevInspect<SKIP_ALL_CHECKS> {
202    type ArgumentUpdates = Vec<(Argument, Vec<u8>, TypeTag)>;
203    type ExecutionResults = Vec<ExecutionResult>;
204
205    fn allow_arbitrary_function_calls() -> bool {
206        SKIP_ALL_CHECKS
207    }
208
209    fn allow_arbitrary_values() -> bool {
210        SKIP_ALL_CHECKS
211    }
212
213    fn skip_conservation_checks() -> bool {
214        SKIP_ALL_CHECKS
215    }
216
217    fn packages_are_predefined() -> bool {
218        false
219    }
220
221    fn empty_arguments() -> Self::ArgumentUpdates {
222        vec![]
223    }
224
225    fn empty_results() -> Self::ExecutionResults {
226        vec![]
227    }
228
229    fn add_argument_update(
230        resolver: &impl TypeTagResolver,
231        acc: &mut Self::ArgumentUpdates,
232        arg: Argument,
233        new_value: &Value,
234    ) -> Result<(), ExecutionError> {
235        let (bytes, type_tag) = value_to_bytes_and_tag(resolver, new_value)?;
236        acc.push((arg, bytes, type_tag));
237        Ok(())
238    }
239
240    fn finish_command(
241        resolver: &impl TypeTagResolver,
242        acc: &mut Self::ExecutionResults,
243        argument_updates: Self::ArgumentUpdates,
244        command_result: &[Value],
245    ) -> Result<(), ExecutionError> {
246        let command_bytes = command_result
247            .iter()
248            .map(|value| value_to_bytes_and_tag(resolver, value))
249            .collect::<Result<_, _>>()?;
250        acc.push((argument_updates, command_bytes));
251        Ok(())
252    }
253}
254
255fn value_to_bytes_and_tag(
256    resolver: &impl TypeTagResolver,
257    value: &Value,
258) -> Result<(Vec<u8>, TypeTag), ExecutionError> {
259    let (type_tag, bytes) = match value {
260        Value::Object(obj) => {
261            let tag = resolver.get_type_tag(&obj.type_)?;
262            let mut bytes = vec![];
263            obj.write_bcs_bytes(&mut bytes);
264            (tag, bytes)
265        }
266        Value::Raw(RawValueType::Any, bytes) => {
267            // this case shouldn't happen
268            (TypeTag::Vector(Box::new(TypeTag::U8)), bytes.clone())
269        }
270        Value::Raw(RawValueType::Loaded { ty, .. }, bytes) => {
271            let tag = resolver.get_type_tag(ty)?;
272            (tag, bytes.clone())
273        }
274        Value::Receiving(id, seqno, _) => (
275            Receiving::type_tag(),
276            Receiving::new(*id, *seqno).to_bcs_bytes(),
277        ),
278    };
279    Ok((bytes, type_tag))
280}