Skip to main content

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_sdk_types::{Argument, StructTag, TypeTag};
6use iota_types::{
7    error::ExecutionError, execution::ExecutionResult, invariant_violation, transfer::Receiving,
8};
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    // == Arg/Result V2 ==
61
62    const TRACK_EXECUTION: bool;
63
64    fn add_argument_update_v2(
65        acc: &mut Self::ArgumentUpdates,
66        arg: Argument,
67        bytes: Vec<u8>,
68        type_: TypeTag,
69    ) -> Result<(), ExecutionError>;
70
71    fn finish_command_v2(
72        acc: &mut Self::ExecutionResults,
73        argument_updates: Vec<(Argument, Vec<u8>, TypeTag)>,
74        command_result: Vec<(Vec<u8>, TypeTag)>,
75    ) -> Result<(), ExecutionError>;
76}
77
78#[derive(Copy, Clone)]
79pub struct Normal;
80
81impl ExecutionMode for Normal {
82    type ArgumentUpdates = ();
83    type ExecutionResults = ();
84
85    fn allow_arbitrary_function_calls() -> bool {
86        false
87    }
88
89    fn allow_arbitrary_values() -> bool {
90        false
91    }
92
93    fn skip_conservation_checks() -> bool {
94        false
95    }
96
97    fn packages_are_predefined() -> bool {
98        false
99    }
100
101    fn empty_arguments() -> Self::ArgumentUpdates {}
102
103    fn empty_results() -> Self::ExecutionResults {}
104
105    fn add_argument_update(
106        _resolver: &impl TypeTagResolver,
107        _acc: &mut Self::ArgumentUpdates,
108        _arg: Argument,
109        _new_value: &Value,
110    ) -> Result<(), ExecutionError> {
111        Ok(())
112    }
113
114    fn finish_command(
115        _resolver: &impl TypeTagResolver,
116        _acc: &mut Self::ExecutionResults,
117        _argument_updates: Self::ArgumentUpdates,
118        _command_result: &[Value],
119    ) -> Result<(), ExecutionError> {
120        Ok(())
121    }
122
123    fn allow_auth_context() -> bool {
124        false
125    }
126
127    const TRACK_EXECUTION: bool = false;
128
129    fn add_argument_update_v2(
130        _acc: &mut Self::ArgumentUpdates,
131        _arg: Argument,
132        _bytes: Vec<u8>,
133        _type_: TypeTag,
134    ) -> Result<(), ExecutionError> {
135        invariant_violation!("should not be called");
136    }
137
138    fn finish_command_v2(
139        _acc: &mut Self::ExecutionResults,
140        _argument_updates: Vec<(Argument, Vec<u8>, TypeTag)>,
141        _command_result: Vec<(Vec<u8>, TypeTag)>,
142    ) -> Result<(), ExecutionError> {
143        invariant_violation!("should not be called");
144    }
145}
146
147#[derive(Copy, Clone)]
148pub struct Genesis;
149
150impl ExecutionMode for Genesis {
151    type ArgumentUpdates = ();
152    type ExecutionResults = ();
153
154    fn allow_arbitrary_function_calls() -> bool {
155        true
156    }
157
158    fn allow_arbitrary_values() -> bool {
159        true
160    }
161
162    fn packages_are_predefined() -> bool {
163        true
164    }
165
166    fn skip_conservation_checks() -> bool {
167        false
168    }
169
170    fn empty_arguments() -> Self::ArgumentUpdates {}
171
172    fn empty_results() -> Self::ExecutionResults {}
173
174    fn add_argument_update(
175        _resolver: &impl TypeTagResolver,
176        _acc: &mut Self::ArgumentUpdates,
177        _arg: Argument,
178        _new_value: &Value,
179    ) -> Result<(), ExecutionError> {
180        Ok(())
181    }
182
183    fn finish_command(
184        _resolver: &impl TypeTagResolver,
185        _acc: &mut Self::ExecutionResults,
186        _argument_updates: Self::ArgumentUpdates,
187        _command_result: &[Value],
188    ) -> Result<(), ExecutionError> {
189        Ok(())
190    }
191
192    fn allow_auth_context() -> bool {
193        false
194    }
195
196    const TRACK_EXECUTION: bool = false;
197
198    fn add_argument_update_v2(
199        _acc: &mut Self::ArgumentUpdates,
200        _arg: Argument,
201        _bytes: Vec<u8>,
202        _type_: TypeTag,
203    ) -> Result<(), ExecutionError> {
204        invariant_violation!("should not be called");
205    }
206
207    fn finish_command_v2(
208        _acc: &mut Self::ExecutionResults,
209        _argument_updates: Vec<(Argument, Vec<u8>, TypeTag)>,
210        _command_result: Vec<(Vec<u8>, TypeTag)>,
211    ) -> Result<(), ExecutionError> {
212        invariant_violation!("should not be called");
213    }
214}
215
216#[derive(Copy, Clone)]
217pub struct System;
218
219/// Execution mode for executing a system transaction, including the epoch
220/// change transaction and the consensus commit prologue. In this mode, we allow
221/// calls to any function bypassing visibility.
222impl ExecutionMode for System {
223    type ArgumentUpdates = ();
224    type ExecutionResults = ();
225
226    fn allow_arbitrary_function_calls() -> bool {
227        // allows bypassing visibility for system calls
228        true
229    }
230
231    fn allow_arbitrary_values() -> bool {
232        // System transactions (e.g. RandomnessStateUpdate) need to pass
233        // arbitrary pure values such as random bytes.
234        true
235    }
236
237    fn skip_conservation_checks() -> bool {
238        false
239    }
240
241    fn packages_are_predefined() -> bool {
242        true
243    }
244
245    fn empty_arguments() -> Self::ArgumentUpdates {}
246
247    fn empty_results() -> Self::ExecutionResults {}
248
249    fn add_argument_update(
250        _resolver: &impl TypeTagResolver,
251        _acc: &mut Self::ArgumentUpdates,
252        _arg: Argument,
253        _new_value: &Value,
254    ) -> Result<(), ExecutionError> {
255        Ok(())
256    }
257
258    fn finish_command(
259        _resolver: &impl TypeTagResolver,
260        _acc: &mut Self::ExecutionResults,
261        _argument_updates: Self::ArgumentUpdates,
262        _command_result: &[Value],
263    ) -> Result<(), ExecutionError> {
264        Ok(())
265    }
266
267    fn allow_auth_context() -> bool {
268        false
269    }
270
271    const TRACK_EXECUTION: bool = false;
272
273    fn add_argument_update_v2(
274        _acc: &mut Self::ArgumentUpdates,
275        _arg: Argument,
276        _bytes: Vec<u8>,
277        _type_: TypeTag,
278    ) -> Result<(), ExecutionError> {
279        invariant_violation!("should not be called");
280    }
281
282    fn finish_command_v2(
283        _acc: &mut Self::ExecutionResults,
284        _argument_updates: Vec<(Argument, Vec<u8>, TypeTag)>,
285        _command_result: Vec<(Vec<u8>, TypeTag)>,
286    ) -> Result<(), ExecutionError> {
287        invariant_violation!("should not be called");
288    }
289}
290
291#[derive(Copy, Clone)]
292pub struct Authentication;
293
294impl ExecutionMode for Authentication {
295    type ArgumentUpdates = ();
296    type ExecutionResults = ();
297
298    fn allow_arbitrary_function_calls() -> bool {
299        false
300    }
301
302    fn allow_arbitrary_values() -> bool {
303        false
304    }
305
306    fn skip_conservation_checks() -> bool {
307        false
308    }
309
310    fn packages_are_predefined() -> bool {
311        false
312    }
313
314    fn empty_arguments() -> Self::ArgumentUpdates {}
315
316    fn empty_results() -> Self::ExecutionResults {}
317
318    fn add_argument_update(
319        _resolver: &impl TypeTagResolver,
320        _acc: &mut Self::ArgumentUpdates,
321        _arg: Argument,
322        _new_value: &Value,
323    ) -> Result<(), ExecutionError> {
324        Ok(())
325    }
326
327    fn finish_command(
328        _resolver: &impl TypeTagResolver,
329        _acc: &mut Self::ExecutionResults,
330        _argument_updates: Self::ArgumentUpdates,
331        _command_result: &[Value],
332    ) -> Result<(), ExecutionError> {
333        Ok(())
334    }
335
336    fn allow_auth_context() -> bool {
337        true
338    }
339
340    const TRACK_EXECUTION: bool = false;
341
342    fn add_argument_update_v2(
343        _acc: &mut Self::ArgumentUpdates,
344        _arg: Argument,
345        _bytes: Vec<u8>,
346        _type_: TypeTag,
347    ) -> Result<(), ExecutionError> {
348        invariant_violation!("should not be called");
349    }
350
351    fn finish_command_v2(
352        _acc: &mut Self::ExecutionResults,
353        _argument_updates: Vec<(Argument, Vec<u8>, TypeTag)>,
354        _command_result: Vec<(Vec<u8>, TypeTag)>,
355    ) -> Result<(), ExecutionError> {
356        invariant_violation!("should not be called");
357    }
358}
359
360/// WARNING! Using this mode will bypass all normal checks around Move entry
361/// functions! This includes the various rules for function arguments, meaning
362/// any object can be created just from BCS bytes!
363pub struct DevInspect<const SKIP_ALL_CHECKS: bool>;
364
365impl<const SKIP_ALL_CHECKS: bool> ExecutionMode for DevInspect<SKIP_ALL_CHECKS> {
366    type ArgumentUpdates = Vec<(Argument, Vec<u8>, TypeTag)>;
367    type ExecutionResults = Vec<ExecutionResult>;
368
369    fn allow_arbitrary_function_calls() -> bool {
370        SKIP_ALL_CHECKS
371    }
372
373    fn allow_arbitrary_values() -> bool {
374        SKIP_ALL_CHECKS
375    }
376
377    fn skip_conservation_checks() -> bool {
378        SKIP_ALL_CHECKS
379    }
380
381    fn packages_are_predefined() -> bool {
382        false
383    }
384
385    fn empty_arguments() -> Self::ArgumentUpdates {
386        vec![]
387    }
388
389    fn empty_results() -> Self::ExecutionResults {
390        vec![]
391    }
392
393    fn add_argument_update(
394        resolver: &impl TypeTagResolver,
395        acc: &mut Self::ArgumentUpdates,
396        arg: Argument,
397        new_value: &Value,
398    ) -> Result<(), ExecutionError> {
399        let (bytes, type_tag) = value_to_bytes_and_tag(resolver, new_value)?;
400        acc.push((arg, bytes, type_tag));
401        Ok(())
402    }
403
404    fn finish_command(
405        resolver: &impl TypeTagResolver,
406        acc: &mut Self::ExecutionResults,
407        argument_updates: Self::ArgumentUpdates,
408        command_result: &[Value],
409    ) -> Result<(), ExecutionError> {
410        let command_bytes = command_result
411            .iter()
412            .map(|value| value_to_bytes_and_tag(resolver, value))
413            .collect::<Result<_, _>>()?;
414        acc.push((argument_updates, command_bytes));
415        Ok(())
416    }
417
418    fn allow_auth_context() -> bool {
419        false
420    }
421
422    const TRACK_EXECUTION: bool = true;
423
424    fn add_argument_update_v2(
425        acc: &mut Self::ArgumentUpdates,
426        arg: Argument,
427        bytes: Vec<u8>,
428        type_: TypeTag,
429    ) -> Result<(), ExecutionError> {
430        acc.push((arg, bytes, type_));
431        Ok(())
432    }
433
434    fn finish_command_v2(
435        acc: &mut Self::ExecutionResults,
436        argument_updates: Vec<(Argument, Vec<u8>, TypeTag)>,
437        command_result: Vec<(Vec<u8>, TypeTag)>,
438    ) -> Result<(), ExecutionError> {
439        acc.push((argument_updates, command_result));
440        Ok(())
441    }
442}
443
444fn value_to_bytes_and_tag(
445    resolver: &impl TypeTagResolver,
446    value: &Value,
447) -> Result<(Vec<u8>, TypeTag), ExecutionError> {
448    let (type_tag, bytes) = match value {
449        Value::Object(obj) => {
450            let tag = resolver.get_type_tag(&obj.type_)?;
451            let mut bytes = vec![];
452            obj.write_bcs_bytes(&mut bytes, None)?;
453            (tag, bytes)
454        }
455        Value::Raw(RawValueType::Any, bytes) => {
456            // this case shouldn't happen
457            (TypeTag::Vector(Box::new(TypeTag::U8)), bytes.clone())
458        }
459        Value::Raw(RawValueType::Loaded { ty, .. }, bytes) => {
460            let tag = resolver.get_type_tag(ty)?;
461            (tag, bytes.clone())
462        }
463        Value::Receiving(id, seqno, assigned_type) => {
464            let Some(ty) = assigned_type else {
465                invariant_violation!("Receiving value used before type assignment");
466            };
467            let value_type = resolver.get_type_tag(ty)?;
468            (
469                StructTag::new_transfer_receiving(value_type).into(),
470                Receiving::new(*id, *seqno).to_bcs_bytes(),
471            )
472        }
473    };
474    Ok((bytes, type_tag))
475}