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