iota_adapter_latest/programmable_transactions/
context.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5pub use checked::*;
6
7#[iota_macros::with_checked_arithmetic]
8mod checked {
9    use std::{
10        borrow::Borrow,
11        collections::{BTreeMap, BTreeSet, HashMap},
12        sync::Arc,
13    };
14
15    use iota_move_natives::object_runtime::{
16        self, LoadedRuntimeObject, ObjectRuntime, RuntimeResults, get_all_uids, max_event_error,
17    };
18    use iota_protocol_config::ProtocolConfig;
19    use iota_types::{
20        balance::Balance,
21        base_types::{IotaAddress, MoveObjectType, ObjectID, TxContext},
22        coin::Coin,
23        error::{ExecutionError, ExecutionErrorKind, command_argument_error},
24        event::Event,
25        execution::{ExecutionResults, ExecutionResultsV1},
26        execution_status::CommandArgumentError,
27        metrics::LimitsMetrics,
28        move_package::MovePackage,
29        object::{Data, MoveObject, Object, ObjectInner, Owner},
30        storage::{BackingPackageStore, DenyListResult, PackageObject},
31        transaction::{Argument, CallArg, ObjectArg},
32    };
33    use move_binary_format::{
34        CompiledModule,
35        errors::{Location, PartialVMError, PartialVMResult, VMError, VMResult},
36        file_format::{CodeOffset, FunctionDefinitionIndex, TypeParameterIndex},
37    };
38    use move_core_types::{
39        account_address::AccountAddress,
40        identifier::IdentStr,
41        language_storage::{ModuleId, StructTag, TypeTag},
42        resolver::ModuleResolver,
43        vm_status::StatusCode,
44    };
45    use move_trace_format::format::MoveTraceBuilder;
46    use move_vm_runtime::{
47        move_vm::MoveVM,
48        native_extensions::NativeContextExtensions,
49        session::{LoadedFunctionInstantiation, SerializedReturnValues},
50    };
51    use move_vm_types::{data_store::DataStore, loaded_data::runtime_types::Type};
52    use tracing::instrument;
53
54    use crate::{
55        adapter::new_native_extensions,
56        error::convert_vm_error,
57        execution_mode::ExecutionMode,
58        execution_value::{
59            CommandKind, ExecutionState, InputObjectMetadata, InputValue, ObjectContents,
60            ObjectValue, RawValueType, ResultValue, TryFromValue, UsageKind, Value,
61        },
62        gas_charger::GasCharger,
63        gas_meter::IotaGasMeter,
64        programmable_transactions::linkage_view::LinkageView,
65        type_resolver::TypeTagResolver,
66    };
67
68    /// Maintains all runtime state specific to programmable transactions
69    pub struct ExecutionContext<'vm, 'state, 'a> {
70        /// The protocol config
71        pub protocol_config: &'a ProtocolConfig,
72        /// Metrics for reporting exceeded limits
73        pub metrics: Arc<LimitsMetrics>,
74        /// The MoveVM
75        pub vm: &'vm MoveVM,
76        /// The LinkageView for this session
77        pub linkage_view: LinkageView<'state>,
78        pub native_extensions: NativeContextExtensions<'state>,
79        /// The global state, used for resolving packages
80        pub state_view: &'state dyn ExecutionState,
81        /// A shared transaction context, contains transaction digest
82        /// information and manages the creation of new object IDs
83        pub tx_context: &'a mut TxContext,
84        /// The gas charger used for metering
85        pub gas_charger: &'a mut GasCharger,
86        /// Additional transfers not from the Move runtime
87        additional_transfers: Vec<(/* new owner */ IotaAddress, ObjectValue)>,
88        /// Newly published packages
89        new_packages: Vec<MovePackage>,
90        /// User events are claimed after each Move call
91        user_events: Vec<(ModuleId, StructTag, Vec<u8>)>,
92        // runtime data
93        /// The runtime value for the Gas coin, None if it has been taken/moved
94        gas: InputValue,
95        /// The runtime value for the inputs/call args, None if it has been
96        /// taken/moved
97        inputs: Vec<InputValue>,
98        /// The results of a given command. For most commands, the inner vector
99        /// will have length 1. It will only not be 1 for Move calls
100        /// with multiple return values. Inner values are None if
101        /// taken/moved by-value
102        results: Vec<Vec<ResultValue>>,
103        /// Map of arguments that are currently borrowed in this command, true
104        /// if the borrow is mutable This gets cleared out when new
105        /// results are pushed, i.e. the end of a command
106        borrowed: HashMap<Arg, /* mut */ bool>,
107    }
108
109    /// A write for an object that was generated outside of the Move
110    /// ObjectRuntime
111    struct AdditionalWrite {
112        /// The new owner of the object
113        recipient: Owner,
114        /// the type of the object,
115        type_: Type,
116        /// contents of the object
117        bytes: Vec<u8>,
118    }
119
120    #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
121    pub struct Arg(Arg_);
122
123    #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
124    enum Arg_ {
125        V1(Argument),
126        V2(NormalizedArg),
127    }
128
129    #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
130    enum NormalizedArg {
131        GasCoin,
132        Input(u16),
133        Result(u16, u16),
134    }
135
136    impl<'vm, 'state, 'a> ExecutionContext<'vm, 'state, 'a> {
137        /// Creates a new instance of the transaction execution context,
138        /// initializing the necessary components such as protocol
139        /// configuration, Move VM, gas management, inputs, and native
140        /// extensions. This function processes the input arguments, sets up gas
141        /// handling for the transaction, and prepares the state for
142        /// executing Move programs.
143        #[instrument(name = "ExecutionContext::new", level = "trace", skip_all)]
144        pub fn new(
145            protocol_config: &'a ProtocolConfig,
146            metrics: Arc<LimitsMetrics>,
147            vm: &'vm MoveVM,
148            state_view: &'state dyn ExecutionState,
149            tx_context: &'a mut TxContext,
150            gas_charger: &'a mut GasCharger,
151            inputs: Vec<CallArg>,
152        ) -> Result<Self, ExecutionError>
153        where
154            'a: 'state,
155        {
156            let mut linkage_view = LinkageView::new(Box::new(state_view.as_iota_resolver()));
157            let mut input_object_map = BTreeMap::new();
158            let inputs = inputs
159                .into_iter()
160                .map(|call_arg| {
161                    load_call_arg(
162                        vm,
163                        state_view,
164                        &mut linkage_view,
165                        &[],
166                        &mut input_object_map,
167                        call_arg,
168                    )
169                })
170                .collect::<Result<_, ExecutionError>>()?;
171            let gas = if let Some(gas_coin) = gas_charger.gas_coin() {
172                let mut gas = load_object(
173                    vm,
174                    state_view,
175                    &mut linkage_view,
176                    &[],
177                    &mut input_object_map,
178                    // imm override
179                    false,
180                    gas_coin,
181                )?;
182                // subtract the max gas budget. This amount is off limits in the programmable
183                // transaction, so to mimic this "off limits" behavior, we act
184                // as if the coin has less balance than it really does
185                let Some(Value::Object(ObjectValue {
186                    contents: ObjectContents::Coin(coin),
187                    ..
188                })) = &mut gas.inner.value
189                else {
190                    invariant_violation!("Gas object should be a populated coin")
191                };
192
193                let max_gas_in_balance = gas_charger.gas_budget();
194                let Some(new_balance) = coin.balance.value().checked_sub(max_gas_in_balance) else {
195                    invariant_violation!(
196                        "Transaction input checker should check that there is enough gas"
197                    );
198                };
199                coin.balance = Balance::new(new_balance);
200                gas
201            } else {
202                InputValue {
203                    object_metadata: None,
204                    inner: ResultValue {
205                        last_usage_kind: None,
206                        value: None,
207                    },
208                }
209            };
210            let native_extensions = new_native_extensions(
211                state_view.as_child_resolver(),
212                input_object_map,
213                !gas_charger.is_unmetered(),
214                protocol_config,
215                metrics.clone(),
216                tx_context.epoch(),
217            );
218
219            // Set the profiler if in CLI
220            #[skip_checked_arithmetic]
221            move_vm_profiler::tracing_feature_enabled! {
222                use move_vm_profiler::GasProfiler;
223                use move_vm_types::gas::GasMeter;
224
225                let tx_digest = tx_context.digest();
226                let remaining_gas: u64 =
227                    move_vm_types::gas::GasMeter::remaining_gas(&IotaGasMeter(gas_charger.move_gas_status_mut()))
228                        .into();
229                IotaGasMeter(gas_charger.move_gas_status_mut())
230                    .set_profiler(GasProfiler::init(
231                        &vm.config().profiler_config,
232                        format!("{tx_digest}"),
233                        remaining_gas,
234                    ));
235            }
236
237            Ok(Self {
238                protocol_config,
239                metrics,
240                vm,
241                linkage_view,
242                native_extensions,
243                state_view,
244                tx_context,
245                gas_charger,
246                gas,
247                inputs,
248                results: vec![],
249                additional_transfers: vec![],
250                new_packages: vec![],
251                user_events: vec![],
252                borrowed: HashMap::new(),
253            })
254        }
255
256        pub fn object_runtime(&self) -> Result<&ObjectRuntime, ExecutionError> {
257            self.native_extensions
258                .get::<ObjectRuntime>()
259                .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))
260        }
261
262        /// Create a new ID and update the state
263        pub fn fresh_id(&mut self) -> Result<ObjectID, ExecutionError> {
264            let object_id = self.tx_context.fresh_id();
265            self.native_extensions
266                .get_mut()
267                .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.new_id(object_id))
268                .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
269            Ok(object_id)
270        }
271
272        /// Delete an ID and update the state
273        pub fn delete_id(&mut self, object_id: ObjectID) -> Result<(), ExecutionError> {
274            self.native_extensions
275                .get_mut()
276                .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.delete_id(object_id))
277                .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))
278        }
279
280        /// Set the link context for the session from the linkage information in
281        /// the MovePackage found at `package_id`.  Returns the runtime
282        /// ID of the link context package on success.
283        pub fn set_link_context(
284            &mut self,
285            package_id: ObjectID,
286        ) -> Result<AccountAddress, ExecutionError> {
287            if self.linkage_view.has_linkage(package_id) {
288                // Setting same context again, can skip.
289                return Ok(self
290                    .linkage_view
291                    .original_package_id()
292                    .unwrap_or(*package_id));
293            }
294
295            let package = package_for_linkage(&self.linkage_view, package_id)
296                .map_err(|e| self.convert_vm_error(e))?;
297
298            self.linkage_view.set_linkage(package.move_package())
299        }
300
301        /// Load a type using the context's current session.
302        pub fn load_type(&mut self, type_tag: &TypeTag) -> VMResult<Type> {
303            load_type(
304                self.vm,
305                &mut self.linkage_view,
306                &self.new_packages,
307                type_tag,
308            )
309        }
310
311        /// Load a type using the context's current session.
312        pub fn load_type_from_struct(&mut self, struct_tag: &StructTag) -> VMResult<Type> {
313            load_type_from_struct(
314                self.vm,
315                &mut self.linkage_view,
316                &self.new_packages,
317                struct_tag,
318            )
319        }
320
321        /// Takes the user events from the runtime and tags them with the Move
322        /// module of the function that was invoked for the command
323        pub fn take_user_events(
324            &mut self,
325            module_id: &ModuleId,
326            function: FunctionDefinitionIndex,
327            last_offset: CodeOffset,
328        ) -> Result<(), ExecutionError> {
329            let events = self
330                .native_extensions
331                .get_mut()
332                .map(|object_runtime: &mut ObjectRuntime| object_runtime.take_user_events())
333                .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
334            let num_events = self.user_events.len() + events.len();
335            let max_events = self.protocol_config.max_num_event_emit();
336            if num_events as u64 > max_events {
337                let err = max_event_error(max_events)
338                    .at_code_offset(function, last_offset)
339                    .finish(Location::Module(module_id.clone()));
340                return Err(self.convert_vm_error(err));
341            }
342            let new_events = events
343                .into_iter()
344                .map(|(ty, tag, value)| {
345                    let layout = self
346                        .vm
347                        .get_runtime()
348                        .type_to_type_layout(&ty)
349                        .map_err(|e| self.convert_vm_error(e))?;
350                    let Some(bytes) = value.simple_serialize(&layout) else {
351                        invariant_violation!("Failed to deserialize already serialized Move value");
352                    };
353                    Ok((module_id.clone(), tag, bytes))
354                })
355                .collect::<Result<Vec<_>, ExecutionError>>()?;
356            self.user_events.extend(new_events);
357            Ok(())
358        }
359
360        /// Takes an iterator of arguments and flattens a Result into a
361        /// NestedResult if there is more than one result.
362        /// However, it is currently gated to 1 result, so this function is in
363        /// place for future changes. This is currently blocked by more
364        /// invasive work needed to update argument idx in errors
365        pub fn splat_args<Items: IntoIterator<Item = Argument>>(
366            &self,
367            start_idx: usize,
368            args: Items,
369        ) -> Result<Vec<Arg>, ExecutionError>
370        where
371            Items::IntoIter: ExactSizeIterator,
372        {
373            if !self.protocol_config.normalize_ptb_arguments() {
374                Ok(args.into_iter().map(|arg| Arg(Arg_::V1(arg))).collect())
375            } else {
376                let args = args.into_iter();
377                let _args_len = args.len();
378                let mut res = vec![];
379                for (arg_idx, arg) in args.enumerate() {
380                    self.splat_arg(&mut res, arg)
381                        .map_err(|e| e.into_execution_error(start_idx + arg_idx))?;
382                }
383                debug_assert_eq!(res.len(), _args_len);
384                Ok(res)
385            }
386        }
387
388        fn splat_arg(&self, res: &mut Vec<Arg>, arg: Argument) -> Result<(), EitherError> {
389            match arg {
390                Argument::GasCoin => res.push(Arg(Arg_::V2(NormalizedArg::GasCoin))),
391                Argument::Input(i) => {
392                    if i as usize >= self.inputs.len() {
393                        return Err(CommandArgumentError::IndexOutOfBounds { idx: i }.into());
394                    }
395                    res.push(Arg(Arg_::V2(NormalizedArg::Input(i))))
396                }
397                Argument::NestedResult(i, j) => {
398                    let Some(command_result) = self.results.get(i as usize) else {
399                        return Err(CommandArgumentError::IndexOutOfBounds { idx: i }.into());
400                    };
401                    if j as usize >= command_result.len() {
402                        return Err(CommandArgumentError::SecondaryIndexOutOfBounds {
403                            result_idx: i,
404                            secondary_idx: j,
405                        }
406                        .into());
407                    };
408                    res.push(Arg(Arg_::V2(NormalizedArg::Result(i, j))))
409                }
410                Argument::Result(i) => {
411                    let Some(result) = self.results.get(i as usize) else {
412                        return Err(CommandArgumentError::IndexOutOfBounds { idx: i }.into());
413                    };
414                    let Ok(len): Result<u16, _> = result.len().try_into() else {
415                        invariant_violation!("Result of length greater than u16::MAX");
416                    };
417                    if len != 1 {
418                        // TODO protocol config to allow splatting of args
419                        return Err(
420                            CommandArgumentError::InvalidResultArity { result_idx: i }.into()
421                        );
422                    }
423                    res.extend((0..len).map(|j| Arg(Arg_::V2(NormalizedArg::Result(i, j)))))
424                }
425            }
426            Ok(())
427        }
428
429        pub fn one_arg(
430            &self,
431            command_arg_idx: usize,
432            arg: Argument,
433        ) -> Result<Arg, ExecutionError> {
434            let args = self.splat_args(command_arg_idx, vec![arg])?;
435            let Ok([arg]): Result<[Arg; 1], _> = args.try_into() else {
436                return Err(command_argument_error(
437                    CommandArgumentError::InvalidArgumentArity,
438                    command_arg_idx,
439                ));
440            };
441            Ok(arg)
442        }
443
444        /// Get the argument value. Cloning the value if it is copyable, and
445        /// setting its value to None if it is not (making it
446        /// unavailable). Errors if out of bounds, if the argument is
447        /// borrowed, if it is unavailable (already taken), or if it is
448        /// an object that cannot be taken by value (shared or immutable)
449        pub fn by_value_arg<V: TryFromValue>(
450            &mut self,
451            command_kind: CommandKind<'_>,
452            arg_idx: usize,
453            arg: Arg,
454        ) -> Result<V, ExecutionError> {
455            self.by_value_arg_(command_kind, arg)
456                .map_err(|e| e.into_execution_error(arg_idx))
457        }
458        fn by_value_arg_<V: TryFromValue>(
459            &mut self,
460            command_kind: CommandKind<'_>,
461            arg: Arg,
462        ) -> Result<V, EitherError> {
463            let is_borrowed = self.arg_is_borrowed(&arg);
464            let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::ByValue)?;
465            let is_copyable = if let Some(val) = val_opt {
466                val.is_copyable()
467            } else {
468                return Err(CommandArgumentError::InvalidValueUsage.into());
469            };
470            // If it was taken, we catch this above.
471            // If it was not copyable and was borrowed, error as it creates a dangling
472            // reference in effect.
473            // We allow copyable values to be copied out even if borrowed, as we do not care
474            // about referential transparency at this level.
475            if !is_copyable && is_borrowed {
476                return Err(CommandArgumentError::InvalidValueUsage.into());
477            }
478            // Gas coin cannot be taken by value, except in TransferObjects
479            if arg.is_gas_coin() && !matches!(command_kind, CommandKind::TransferObjects) {
480                return Err(CommandArgumentError::InvalidGasCoinUsage.into());
481            }
482            // Immutable objects cannot be taken by value
483            if matches!(
484                input_metadata_opt,
485                Some(InputObjectMetadata::InputObject {
486                    owner: Owner::Immutable,
487                    ..
488                })
489            ) {
490                return Err(CommandArgumentError::InvalidObjectByValue.into());
491            }
492
493            // Any input object taken by value must be mutable
494            if matches!(
495                input_metadata_opt,
496                Some(InputObjectMetadata::InputObject {
497                    is_mutable_input: false,
498                    ..
499                })
500            ) {
501                return Err(CommandArgumentError::InvalidObjectByValue.into());
502            }
503
504            let val = if is_copyable {
505                val_opt.as_ref().unwrap().clone()
506            } else {
507                val_opt.take().unwrap()
508            };
509            Ok(V::try_from_value(val)?)
510        }
511
512        /// Mimic a mutable borrow by taking the argument value, setting its
513        /// value to None, making it unavailable. The value will be
514        /// marked as borrowed and must be returned with restore_arg
515        /// Errors if out of bounds, if the argument is borrowed, if it is
516        /// unavailable (already taken), or if it is an object that
517        /// cannot be mutably borrowed (immutable)
518        pub fn borrow_arg_mut<V: TryFromValue>(
519            &mut self,
520            arg_idx: usize,
521            arg: Arg,
522        ) -> Result<V, ExecutionError> {
523            self.borrow_arg_mut_(arg)
524                .map_err(|e| e.into_execution_error(arg_idx))
525        }
526        fn borrow_arg_mut_<V: TryFromValue>(&mut self, arg: Arg) -> Result<V, EitherError> {
527            // mutable borrowing requires unique usage
528            if self.arg_is_borrowed(&arg) {
529                return Err(CommandArgumentError::InvalidValueUsage.into());
530            }
531            self.borrowed.insert(arg, /* is_mut */ true);
532            let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowMut)?;
533            let is_copyable = if let Some(val) = val_opt {
534                val.is_copyable()
535            } else {
536                // error if taken
537                return Err(CommandArgumentError::InvalidValueUsage.into());
538            };
539            if let Some(InputObjectMetadata::InputObject {
540                is_mutable_input: false,
541                ..
542            }) = input_metadata_opt
543            {
544                return Err(CommandArgumentError::InvalidObjectByMutRef.into());
545            }
546            // if it is copyable, don't take it as we allow for the value to be copied even
547            // if mutably borrowed
548            let val = if is_copyable {
549                val_opt.as_ref().unwrap().clone()
550            } else {
551                val_opt.take().unwrap()
552            };
553            Ok(V::try_from_value(val)?)
554        }
555
556        /// Mimics an immutable borrow by cloning the argument value without
557        /// setting its value to None Errors if out of bounds, if the
558        /// argument is mutably borrowed, or if it is unavailable
559        /// (already taken)
560        pub fn borrow_arg<V: TryFromValue>(
561            &mut self,
562            arg_idx: usize,
563            arg: Arg,
564            type_: &Type,
565        ) -> Result<V, ExecutionError> {
566            self.borrow_arg_(arg, type_)
567                .map_err(|e| e.into_execution_error(arg_idx))
568        }
569        fn borrow_arg_<V: TryFromValue>(
570            &mut self,
571            arg: Arg,
572            arg_type: &Type,
573        ) -> Result<V, EitherError> {
574            // immutable borrowing requires the value was not mutably borrowed.
575            // If it was copied, that is okay.
576            // If it was taken/moved, we will find out below
577            if self.arg_is_mut_borrowed(&arg) {
578                return Err(CommandArgumentError::InvalidValueUsage.into());
579            }
580            self.borrowed.insert(arg, /* is_mut */ false);
581            let (_input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowImm)?;
582            if val_opt.is_none() {
583                return Err(CommandArgumentError::InvalidValueUsage.into());
584            }
585
586            // We eagerly reify receiving argument types at the first usage of them.
587            if let &mut Some(Value::Receiving(_, _, ref mut recv_arg_type @ None)) = val_opt {
588                let Type::Reference(inner) = arg_type else {
589                    return Err(CommandArgumentError::InvalidValueUsage.into());
590                };
591                *recv_arg_type = Some(*(*inner).clone());
592            }
593
594            Ok(V::try_from_value(val_opt.as_ref().unwrap().clone())?)
595        }
596
597        /// Restore an argument after being mutably borrowed
598        pub fn restore_arg<Mode: ExecutionMode>(
599            &mut self,
600            updates: &mut Mode::ArgumentUpdates,
601            arg: Arg,
602            value: Value,
603        ) -> Result<(), ExecutionError> {
604            Mode::add_argument_update(self, updates, arg.into(), &value)?;
605            let was_mut_opt = self.borrowed.remove(&arg);
606            assert_invariant!(
607                was_mut_opt.is_some() && was_mut_opt.unwrap(),
608                "Should never restore a non-mut borrowed value. \
609                The take+restore is an implementation detail of mutable references"
610            );
611            // restore is exclusively used for mut
612            let Ok((_, value_opt)) = self.borrow_mut_impl(arg, None) else {
613                invariant_violation!("Should be able to borrow argument to restore it")
614            };
615
616            let old_value = value_opt.replace(value);
617            assert_invariant!(
618                old_value.is_none() || old_value.unwrap().is_copyable(),
619                "Should never restore a non-taken value, unless it is copyable. \
620                The take+restore is an implementation detail of mutable references"
621            );
622
623            Ok(())
624        }
625
626        /// Transfer the object to a new owner
627        pub fn transfer_object(
628            &mut self,
629            obj: ObjectValue,
630            addr: IotaAddress,
631        ) -> Result<(), ExecutionError> {
632            self.additional_transfers.push((addr, obj));
633            Ok(())
634        }
635
636        /// Create a new package
637        pub fn new_package<'p>(
638            &self,
639            modules: &[CompiledModule],
640            dependencies: impl IntoIterator<Item = &'p MovePackage>,
641        ) -> Result<MovePackage, ExecutionError> {
642            MovePackage::new_initial(modules, self.protocol_config, dependencies)
643        }
644
645        /// Create a package upgrade from `previous_package` with `new_modules`
646        /// and `dependencies`
647        pub fn upgrade_package<'p>(
648            &self,
649            storage_id: ObjectID,
650            previous_package: &MovePackage,
651            new_modules: &[CompiledModule],
652            dependencies: impl IntoIterator<Item = &'p MovePackage>,
653        ) -> Result<MovePackage, ExecutionError> {
654            previous_package.new_upgraded(
655                storage_id,
656                new_modules,
657                self.protocol_config,
658                dependencies,
659            )
660        }
661
662        /// Add a newly created package to write as an effect of the transaction
663        pub fn write_package(&mut self, package: MovePackage) {
664            self.new_packages.push(package);
665        }
666
667        /// Return the last package pushed in `write_package`.
668        /// This function should be used in block of codes that push a package,
669        /// verify it, run the init and in case of error will remove the
670        /// package. The package has to be pushed for the init to run
671        /// correctly.
672        pub fn pop_package(&mut self) -> Option<MovePackage> {
673            self.new_packages.pop()
674        }
675
676        /// Finish a command: clearing the borrows and adding the results to the
677        /// result vector
678        pub fn push_command_results(&mut self, results: Vec<Value>) -> Result<(), ExecutionError> {
679            assert_invariant!(
680                self.borrowed.values().all(|is_mut| !is_mut),
681                "all mut borrows should be restored"
682            );
683            // clear borrow state
684            self.borrowed = HashMap::new();
685            self.results
686                .push(results.into_iter().map(ResultValue::new).collect());
687            Ok(())
688        }
689
690        /// Determine the object changes and collect all user events
691        pub fn finish<Mode: ExecutionMode>(self) -> Result<ExecutionResults, ExecutionError> {
692            let Self {
693                protocol_config,
694                vm,
695                linkage_view,
696                mut native_extensions,
697                tx_context,
698                gas_charger,
699                additional_transfers,
700                new_packages,
701                gas,
702                inputs,
703                results,
704                user_events,
705                state_view,
706                ..
707            } = self;
708            let tx_digest = tx_context.digest();
709            let gas_id_opt = gas.object_metadata.as_ref().map(|info| info.id());
710            let mut loaded_runtime_objects = BTreeMap::new();
711            let mut additional_writes = BTreeMap::new();
712            let mut by_value_shared_objects = BTreeSet::new();
713            for input in inputs.into_iter().chain(std::iter::once(gas)) {
714                let InputValue {
715                    object_metadata:
716                        Some(InputObjectMetadata::InputObject {
717                            // We are only interested in mutable inputs.
718                            is_mutable_input: true,
719                            id,
720                            version,
721                            owner,
722                        }),
723                    inner: ResultValue { value, .. },
724                } = input
725                else {
726                    continue;
727                };
728                loaded_runtime_objects.insert(
729                    id,
730                    LoadedRuntimeObject {
731                        version,
732                        is_modified: true,
733                    },
734                );
735                if let Some(Value::Object(object_value)) = value {
736                    add_additional_write(&mut additional_writes, owner, object_value)?;
737                } else if owner.is_shared() {
738                    by_value_shared_objects.insert(id);
739                }
740            }
741            // check for unused values
742            // disable this check for dev inspect
743            if !Mode::allow_arbitrary_values() {
744                for (i, command_result) in results.iter().enumerate() {
745                    for (j, result_value) in command_result.iter().enumerate() {
746                        let ResultValue {
747                            last_usage_kind,
748                            value,
749                        } = result_value;
750                        match value {
751                            None => (),
752                            Some(Value::Object(_)) => {
753                                return Err(ExecutionErrorKind::UnusedValueWithoutDrop {
754                                    result_idx: i as u16,
755                                    secondary_idx: j as u16,
756                                }
757                                .into());
758                            }
759                            Some(Value::Raw(RawValueType::Any, _)) => (),
760                            Some(Value::Raw(RawValueType::Loaded { abilities, .. }, _)) => {
761                                // - nothing to check for drop
762                                // - if it does not have drop, but has copy, the last usage must be
763                                //   by value in order to "lie" and say that the last usage is
764                                //   actually a take instead of a clone
765                                // - Otherwise, an error
766                                if abilities.has_drop()
767                                    || (abilities.has_copy()
768                                        && matches!(last_usage_kind, Some(UsageKind::ByValue)))
769                                {
770                                } else {
771                                    let msg = if abilities.has_copy() {
772                                        "The value has copy, but not drop. \
773                                        Its last usage must be by-value so it can be taken."
774                                    } else {
775                                        "Unused value without drop"
776                                    };
777                                    return Err(ExecutionError::new_with_source(
778                                        ExecutionErrorKind::UnusedValueWithoutDrop {
779                                            result_idx: i as u16,
780                                            secondary_idx: j as u16,
781                                        },
782                                        msg,
783                                    ));
784                                }
785                            }
786                            // Receiving arguments can be dropped without being received
787                            Some(Value::Receiving(_, _, _)) => (),
788                        }
789                    }
790                }
791            }
792            // add transfers from TransferObjects command
793            for (recipient, object_value) in additional_transfers {
794                let owner = Owner::AddressOwner(recipient);
795                add_additional_write(&mut additional_writes, owner, object_value)?;
796            }
797            // Refund unused gas
798            if let Some(gas_id) = gas_id_opt {
799                refund_max_gas_budget(&mut additional_writes, gas_charger, gas_id)?;
800            }
801
802            let object_runtime: ObjectRuntime = native_extensions
803                .remove()
804                .map_err(|e| convert_vm_error(e.finish(Location::Undefined), vm, &linkage_view))?;
805
806            let RuntimeResults {
807                writes,
808                user_events: remaining_events,
809                loaded_child_objects,
810                mut created_object_ids,
811                deleted_object_ids,
812            } = object_runtime.finish()?;
813            assert_invariant!(
814                remaining_events.is_empty(),
815                "Events should be taken after every Move call"
816            );
817
818            loaded_runtime_objects.extend(loaded_child_objects);
819
820            let mut written_objects = BTreeMap::new();
821            for package in new_packages {
822                let package_obj = Object::new_from_package(package, tx_digest);
823                let id = package_obj.id();
824                created_object_ids.insert(id);
825                written_objects.insert(id, package_obj);
826            }
827            for (id, additional_write) in additional_writes {
828                let AdditionalWrite {
829                    recipient,
830                    type_,
831                    bytes,
832                } = additional_write;
833
834                let move_object = {
835                    create_written_object(
836                        vm,
837                        &linkage_view,
838                        protocol_config,
839                        &loaded_runtime_objects,
840                        id,
841                        type_,
842                        bytes,
843                    )?
844                };
845                let object = Object::new_move(move_object, recipient, tx_digest);
846                written_objects.insert(id, object);
847                if let Some(loaded) = loaded_runtime_objects.get_mut(&id) {
848                    loaded.is_modified = true;
849                }
850            }
851
852            for (id, (recipient, ty, value)) in writes {
853                let layout = vm
854                    .get_runtime()
855                    .type_to_type_layout(&ty)
856                    .map_err(|e| convert_vm_error(e, vm, &linkage_view))?;
857                let Some(bytes) = value.simple_serialize(&layout) else {
858                    invariant_violation!("Failed to deserialize already serialized Move value");
859                };
860                let move_object = {
861                    create_written_object(
862                        vm,
863                        &linkage_view,
864                        protocol_config,
865                        &loaded_runtime_objects,
866                        id,
867                        ty,
868                        bytes,
869                    )?
870                };
871                let object = Object::new_move(move_object, recipient, tx_digest);
872                written_objects.insert(id, object);
873            }
874
875            // Before finishing, ensure that any shared object taken by value by the
876            // transaction is either:
877            // 1. Mutated (and still has a shared ownership); or
878            // 2. Deleted.
879            // Otherwise, the shared object operation is not allowed and we fail the
880            // transaction.
881            for id in &by_value_shared_objects {
882                // If it's been written it must have been reshared so must still have an
883                // ownership of `Shared`.
884                if let Some(obj) = written_objects.get(id) {
885                    if !obj.is_shared() {
886                        return Err(ExecutionError::new(
887                            ExecutionErrorKind::SharedObjectOperationNotAllowed,
888                            Some(
889                                format!(
890                                    "Shared object operation on {id} not allowed: \
891                                     cannot be frozen, transferred, or wrapped"
892                                )
893                                .into(),
894                            ),
895                        ));
896                    }
897                } else {
898                    // If it's not in the written objects, the object must have been deleted.
899                    // Otherwise it's an error.
900                    if !deleted_object_ids.contains(id) {
901                        return Err(ExecutionError::new(
902                            ExecutionErrorKind::SharedObjectOperationNotAllowed,
903                            Some(
904                                format!("Shared object operation on {id} not allowed: \
905                                         shared objects used by value must be re-shared if not deleted").into(),
906                            ),
907                        ));
908                    }
909                }
910            }
911
912            let DenyListResult {
913                result,
914                num_non_gas_coin_owners,
915            } = state_view.check_coin_deny_list(&written_objects);
916            gas_charger.charge_coin_transfers(protocol_config, num_non_gas_coin_owners)?;
917            result?;
918
919            let user_events = user_events
920                .into_iter()
921                .map(|(module_id, tag, contents)| {
922                    Event::new(
923                        module_id.address(),
924                        module_id.name(),
925                        tx_context.sender(),
926                        tag,
927                        contents,
928                    )
929                })
930                .collect();
931
932            Ok(ExecutionResults::V1(ExecutionResultsV1 {
933                written_objects,
934                modified_objects: loaded_runtime_objects
935                    .into_iter()
936                    .filter_map(|(id, loaded)| loaded.is_modified.then_some(id))
937                    .collect(),
938                created_object_ids: created_object_ids.into_iter().collect(),
939                deleted_object_ids: deleted_object_ids.into_iter().collect(),
940                user_events,
941            }))
942        }
943
944        /// Convert a VM Error to an execution one
945        pub fn convert_vm_error(&self, error: VMError) -> ExecutionError {
946            crate::error::convert_vm_error(error, self.vm, &self.linkage_view)
947        }
948
949        /// Special case errors for type arguments to Move functions
950        pub fn convert_type_argument_error(&self, idx: usize, error: VMError) -> ExecutionError {
951            use iota_types::execution_status::TypeArgumentError;
952            use move_core_types::vm_status::StatusCode;
953            match error.major_status() {
954                StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
955                    ExecutionErrorKind::TypeArityMismatch.into()
956                }
957                StatusCode::TYPE_RESOLUTION_FAILURE => ExecutionErrorKind::TypeArgumentError {
958                    argument_idx: idx as TypeParameterIndex,
959                    kind: TypeArgumentError::TypeNotFound,
960                }
961                .into(),
962                StatusCode::CONSTRAINT_NOT_SATISFIED => ExecutionErrorKind::TypeArgumentError {
963                    argument_idx: idx as TypeParameterIndex,
964                    kind: TypeArgumentError::ConstraintNotSatisfied,
965                }
966                .into(),
967                _ => self.convert_vm_error(error),
968            }
969        }
970
971        /// Returns true if the value at the argument's location is borrowed,
972        /// mutably or immutably
973        fn arg_is_borrowed(&self, arg: &Arg) -> bool {
974            self.borrowed.contains_key(arg)
975        }
976
977        /// Returns true if the value at the argument's location is mutably
978        /// borrowed
979        fn arg_is_mut_borrowed(&self, arg: &Arg) -> bool {
980            matches!(self.borrowed.get(arg), Some(/* mut */ true))
981        }
982
983        /// Internal helper to borrow the value for an argument and update the
984        /// most recent usage
985        fn borrow_mut(
986            &mut self,
987            arg: Arg,
988            usage: UsageKind,
989        ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), EitherError> {
990            self.borrow_mut_impl(arg, Some(usage))
991        }
992
993        /// Internal helper to borrow the value for an argument
994        /// Updates the most recent usage if specified
995        fn borrow_mut_impl(
996            &mut self,
997            arg: Arg,
998            update_last_usage: Option<UsageKind>,
999        ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), EitherError> {
1000            match arg.0 {
1001                Arg_::V1(arg) => {
1002                    assert_invariant!(
1003                        !self.protocol_config.normalize_ptb_arguments(),
1004                        "Should not be using v1 args with normalized args"
1005                    );
1006                    Ok(self.borrow_mut_impl_v1(arg, update_last_usage)?)
1007                }
1008                Arg_::V2(arg) => {
1009                    assert_invariant!(
1010                        self.protocol_config.normalize_ptb_arguments(),
1011                        "Should be using only v2 args with normalized args"
1012                    );
1013                    Ok(self.borrow_mut_impl_v2(arg, update_last_usage)?)
1014                }
1015            }
1016        }
1017
1018        // v1 of borrow_mut_impl
1019        fn borrow_mut_impl_v1(
1020            &mut self,
1021            arg: Argument,
1022            update_last_usage: Option<UsageKind>,
1023        ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), CommandArgumentError>
1024        {
1025            let (metadata, result_value) = match arg {
1026                Argument::GasCoin => (self.gas.object_metadata.as_ref(), &mut self.gas.inner),
1027                Argument::Input(i) => {
1028                    let Some(input_value) = self.inputs.get_mut(i as usize) else {
1029                        return Err(CommandArgumentError::IndexOutOfBounds { idx: i });
1030                    };
1031                    (input_value.object_metadata.as_ref(), &mut input_value.inner)
1032                }
1033                Argument::Result(i) => {
1034                    let Some(command_result) = self.results.get_mut(i as usize) else {
1035                        return Err(CommandArgumentError::IndexOutOfBounds { idx: i });
1036                    };
1037                    if command_result.len() != 1 {
1038                        return Err(CommandArgumentError::InvalidResultArity { result_idx: i });
1039                    }
1040                    (None, &mut command_result[0])
1041                }
1042                Argument::NestedResult(i, j) => {
1043                    let Some(command_result) = self.results.get_mut(i as usize) else {
1044                        return Err(CommandArgumentError::IndexOutOfBounds { idx: i });
1045                    };
1046                    let Some(result_value) = command_result.get_mut(j as usize) else {
1047                        return Err(CommandArgumentError::SecondaryIndexOutOfBounds {
1048                            result_idx: i,
1049                            secondary_idx: j,
1050                        });
1051                    };
1052                    (None, result_value)
1053                }
1054            };
1055            if let Some(usage) = update_last_usage {
1056                result_value.last_usage_kind = Some(usage);
1057            }
1058            Ok((metadata, &mut result_value.value))
1059        }
1060
1061        // v2 of borrow_mut_impl
1062        fn borrow_mut_impl_v2(
1063            &mut self,
1064            arg: NormalizedArg,
1065            update_last_usage: Option<UsageKind>,
1066        ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), ExecutionError> {
1067            let (metadata, result_value) = match arg {
1068                NormalizedArg::GasCoin => (self.gas.object_metadata.as_ref(), &mut self.gas.inner),
1069                NormalizedArg::Input(i) => {
1070                    let input_value = self
1071                        .inputs
1072                        .get_mut(i as usize)
1073                        .ok_or_else(|| make_invariant_violation!("bounds already checked"))?;
1074                    (input_value.object_metadata.as_ref(), &mut input_value.inner)
1075                }
1076                NormalizedArg::Result(i, j) => {
1077                    let result_value = self
1078                        .results
1079                        .get_mut(i as usize)
1080                        .ok_or_else(|| make_invariant_violation!("bounds already checked"))?
1081                        .get_mut(j as usize)
1082                        .ok_or_else(|| make_invariant_violation!("bounds already checked"))?;
1083                    (None, result_value)
1084                }
1085            };
1086            if let Some(usage) = update_last_usage {
1087                result_value.last_usage_kind = Some(usage);
1088            }
1089            Ok((metadata, &mut result_value.value))
1090        }
1091
1092        /// Executes a Move function bypassing visibility checks, allowing the
1093        /// execution of private or protected functions. This method
1094        /// sets up the necessary gas status and data store, and then
1095        /// delegates the execution to the Move VM runtime.
1096        pub(crate) fn execute_function_bypass_visibility(
1097            &mut self,
1098            module: &ModuleId,
1099            function_name: &IdentStr,
1100            ty_args: Vec<Type>,
1101            args: Vec<impl Borrow<[u8]>>,
1102            tracer: &mut Option<MoveTraceBuilder>,
1103        ) -> VMResult<SerializedReturnValues> {
1104            let gas_status = self.gas_charger.move_gas_status_mut();
1105            let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1106            self.vm.get_runtime().execute_function_bypass_visibility(
1107                module,
1108                function_name,
1109                ty_args,
1110                args,
1111                &mut data_store,
1112                &mut IotaGasMeter(gas_status),
1113                &mut self.native_extensions,
1114                tracer.as_mut(),
1115            )
1116        }
1117
1118        /// Loads a Move function from the specified module with the given type
1119        /// arguments without executing it. This function initializes
1120        /// the data store and delegates the loading process to the Move
1121        /// VM runtime.
1122        pub(crate) fn load_function(
1123            &mut self,
1124            module_id: &ModuleId,
1125            function_name: &IdentStr,
1126            type_arguments: &[Type],
1127        ) -> VMResult<LoadedFunctionInstantiation> {
1128            let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1129            self.vm.get_runtime().load_function(
1130                module_id,
1131                function_name,
1132                type_arguments,
1133                &mut data_store,
1134            )
1135        }
1136
1137        /// Constructs an `ObjectValue` based on the provided Move object type,
1138        /// transferability, usage context, and byte contents. This
1139        /// function utilizes the protocol configuration, Move VM, and
1140        /// linkage view to properly interpret and instantiate the object.
1141        pub(crate) fn make_object_value(
1142            &mut self,
1143            type_: MoveObjectType,
1144            used_in_non_entry_move_call: bool,
1145            contents: &[u8],
1146        ) -> Result<ObjectValue, ExecutionError> {
1147            make_object_value(
1148                self.vm,
1149                &mut self.linkage_view,
1150                &self.new_packages,
1151                type_,
1152                used_in_non_entry_move_call,
1153                contents,
1154            )
1155        }
1156
1157        /// Publishes a bundle of Move modules to the blockchain under the
1158        /// specified sender's account address. The function initializes
1159        /// a data store and delegates the publishing operation to the Move VM
1160        /// runtime.
1161        pub fn publish_module_bundle(
1162            &mut self,
1163            modules: Vec<Vec<u8>>,
1164            sender: AccountAddress,
1165        ) -> VMResult<()> {
1166            // TODO: publish_module_bundle() currently doesn't charge gas.
1167            // Do we want to charge there?
1168            let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1169            self.vm.get_runtime().publish_module_bundle(
1170                modules,
1171                sender,
1172                &mut data_store,
1173                &mut IotaGasMeter(self.gas_charger.move_gas_status_mut()),
1174            )
1175        }
1176    }
1177
1178    impl TypeTagResolver for ExecutionContext<'_, '_, '_> {
1179        /// Retrieves the `TypeTag` corresponding to the provided `Type` by
1180        /// querying the Move VM runtime.
1181        fn get_type_tag(&self, type_: &Type) -> Result<TypeTag, ExecutionError> {
1182            self.vm
1183                .get_runtime()
1184                .get_type_tag(type_)
1185                .map_err(|e| self.convert_vm_error(e))
1186        }
1187    }
1188
1189    /// Fetch the package at `package_id` with a view to using it as a link
1190    /// context.  Produces an error if the object at that ID does not exist,
1191    /// or is not a package.
1192    fn package_for_linkage(
1193        linkage_view: &LinkageView,
1194        package_id: ObjectID,
1195    ) -> VMResult<PackageObject> {
1196        use move_binary_format::errors::PartialVMError;
1197        use move_core_types::vm_status::StatusCode;
1198
1199        match linkage_view.get_package_object(&package_id) {
1200            Ok(Some(package)) => Ok(package),
1201            Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1202                .with_message(format!("Cannot find link context {package_id} in store"))
1203                .finish(Location::Undefined)),
1204            Err(err) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1205                .with_message(format!(
1206                    "Error loading link context {package_id} from store: {err}"
1207                ))
1208                .finish(Location::Undefined)),
1209        }
1210    }
1211
1212    /// Loads a `Type` from the given `StructTag`, retrieving the corresponding
1213    /// struct from the package in storage. The function sets up the linkage
1214    /// context to resolve the struct's module and verifies
1215    /// any type parameter constraints. If the struct has type parameters, they
1216    /// are recursively loaded and verified.
1217    pub fn load_type_from_struct(
1218        vm: &MoveVM,
1219        linkage_view: &mut LinkageView,
1220        new_packages: &[MovePackage],
1221        struct_tag: &StructTag,
1222    ) -> VMResult<Type> {
1223        fn verification_error<T>(code: StatusCode) -> VMResult<T> {
1224            Err(PartialVMError::new(code).finish(Location::Undefined))
1225        }
1226
1227        let StructTag {
1228            address,
1229            module,
1230            name,
1231            type_params,
1232        } = struct_tag;
1233
1234        // Load the package that the struct is defined in, in storage
1235        let defining_id = ObjectID::from_address(*address);
1236        let package = package_for_linkage(linkage_view, defining_id)?;
1237
1238        // Set the defining package as the link context while loading the
1239        // struct
1240        let original_address = linkage_view
1241            .set_linkage(package.move_package())
1242            .map_err(|e| {
1243                PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1244                    .with_message(e.to_string())
1245                    .finish(Location::Undefined)
1246            })?;
1247
1248        let runtime_id = ModuleId::new(original_address, module.clone());
1249        let data_store = IotaDataStore::new(linkage_view, new_packages);
1250        let res = vm.get_runtime().load_type(&runtime_id, name, &data_store);
1251        linkage_view.reset_linkage();
1252        let (idx, struct_type) = res?;
1253
1254        // Recursively load type parameters, if necessary
1255        let type_param_constraints = struct_type.type_param_constraints();
1256        if type_param_constraints.len() != type_params.len() {
1257            return verification_error(StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH);
1258        }
1259
1260        if type_params.is_empty() {
1261            Ok(Type::Datatype(idx))
1262        } else {
1263            let loaded_type_params = type_params
1264                .iter()
1265                .map(|type_param| load_type(vm, linkage_view, new_packages, type_param))
1266                .collect::<VMResult<Vec<_>>>()?;
1267
1268            // Verify that the type parameter constraints on the struct are met
1269            for (constraint, param) in type_param_constraints.zip(&loaded_type_params) {
1270                let abilities = vm.get_runtime().get_type_abilities(param)?;
1271                if !constraint.is_subset(abilities) {
1272                    return verification_error(StatusCode::CONSTRAINT_NOT_SATISFIED);
1273                }
1274            }
1275
1276            Ok(Type::DatatypeInstantiation(Box::new((
1277                idx,
1278                loaded_type_params,
1279            ))))
1280        }
1281    }
1282
1283    /// Load `type_tag` to get a `Type` in the provided `session`.  `session`'s
1284    /// linkage context may be reset after this operation, because during
1285    /// the operation, it may change when loading a struct.
1286    pub fn load_type(
1287        vm: &MoveVM,
1288        linkage_view: &mut LinkageView,
1289        new_packages: &[MovePackage],
1290        type_tag: &TypeTag,
1291    ) -> VMResult<Type> {
1292        Ok(match type_tag {
1293            TypeTag::Bool => Type::Bool,
1294            TypeTag::U8 => Type::U8,
1295            TypeTag::U16 => Type::U16,
1296            TypeTag::U32 => Type::U32,
1297            TypeTag::U64 => Type::U64,
1298            TypeTag::U128 => Type::U128,
1299            TypeTag::U256 => Type::U256,
1300            TypeTag::Address => Type::Address,
1301            TypeTag::Signer => Type::Signer,
1302
1303            TypeTag::Vector(inner) => {
1304                Type::Vector(Box::new(load_type(vm, linkage_view, new_packages, inner)?))
1305            }
1306            TypeTag::Struct(struct_tag) => {
1307                return load_type_from_struct(vm, linkage_view, new_packages, struct_tag);
1308            }
1309        })
1310    }
1311
1312    /// Constructs an `ObjectValue` based on the provided `MoveObjectType`,
1313    /// contents, and additional flags such as transferability and usage
1314    /// context. If the object is a coin, it deserializes the contents into
1315    /// a `Coin` type; otherwise, it treats the contents as raw data. The
1316    /// function then loads the corresponding struct type from the Move
1317    /// package and verifies its abilities if needed.
1318    pub(crate) fn make_object_value(
1319        vm: &MoveVM,
1320        linkage_view: &mut LinkageView,
1321        new_packages: &[MovePackage],
1322        type_: MoveObjectType,
1323        used_in_non_entry_move_call: bool,
1324        contents: &[u8],
1325    ) -> Result<ObjectValue, ExecutionError> {
1326        let contents = if type_.is_coin() {
1327            let Ok(coin) = Coin::from_bcs_bytes(contents) else {
1328                invariant_violation!("Could not deserialize a coin")
1329            };
1330            ObjectContents::Coin(coin)
1331        } else {
1332            ObjectContents::Raw(contents.to_vec())
1333        };
1334
1335        let tag: StructTag = type_.into();
1336        let type_ = load_type_from_struct(vm, linkage_view, new_packages, &tag)
1337            .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1338        let abilities = vm
1339            .get_runtime()
1340            .get_type_abilities(&type_)
1341            .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1342        let has_public_transfer = abilities.has_store();
1343        Ok(ObjectValue {
1344            type_,
1345            has_public_transfer,
1346            used_in_non_entry_move_call,
1347            contents,
1348        })
1349    }
1350
1351    impl Arg {
1352        fn is_gas_coin(&self) -> bool {
1353            // kept as two separate matches for exhaustiveness
1354            match self {
1355                Arg(Arg_::V1(a)) => matches!(a, Argument::GasCoin),
1356                Arg(Arg_::V2(n)) => matches!(n, NormalizedArg::GasCoin),
1357            }
1358        }
1359    }
1360
1361    impl From<Arg> for Argument {
1362        fn from(arg: Arg) -> Self {
1363            match arg.0 {
1364                Arg_::V1(a) => a,
1365                Arg_::V2(normalized) => match normalized {
1366                    NormalizedArg::GasCoin => Argument::GasCoin,
1367                    NormalizedArg::Input(i) => Argument::Input(i),
1368                    NormalizedArg::Result(i, j) => Argument::NestedResult(i, j),
1369                },
1370            }
1371        }
1372    }
1373
1374    /// Converts a provided `Object` into an `ObjectValue`, extracting and
1375    /// validating the `MoveObjectType` and contents. This function assumes
1376    /// the object contains Move-specific data and passes the extracted data
1377    /// through `make_object_value` to create the corresponding `ObjectValue`.
1378    pub(crate) fn value_from_object(
1379        vm: &MoveVM,
1380        linkage_view: &mut LinkageView,
1381        new_packages: &[MovePackage],
1382        object: &Object,
1383    ) -> Result<ObjectValue, ExecutionError> {
1384        let ObjectInner {
1385            data: Data::Move(object),
1386            ..
1387        } = object.as_inner()
1388        else {
1389            invariant_violation!("Expected a Move object");
1390        };
1391
1392        let used_in_non_entry_move_call = false;
1393        make_object_value(
1394            vm,
1395            linkage_view,
1396            new_packages,
1397            object.type_().clone(),
1398            used_in_non_entry_move_call,
1399            object.contents(),
1400        )
1401    }
1402
1403    /// Load an input object from the state_view
1404    fn load_object(
1405        vm: &MoveVM,
1406        state_view: &dyn ExecutionState,
1407        linkage_view: &mut LinkageView,
1408        new_packages: &[MovePackage],
1409        input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1410        override_as_immutable: bool,
1411        id: ObjectID,
1412    ) -> Result<InputValue, ExecutionError> {
1413        let Some(obj) = state_view.read_object(&id) else {
1414            // protected by transaction input checker
1415            invariant_violation!("Object {} does not exist yet", id);
1416        };
1417        // override_as_immutable ==> Owner::Shared
1418        assert_invariant!(
1419            !override_as_immutable || matches!(obj.owner, Owner::Shared { .. }),
1420            "override_as_immutable should only be set for shared objects"
1421        );
1422        let is_mutable_input = match obj.owner {
1423            Owner::AddressOwner(_) => true,
1424            Owner::Shared { .. } => !override_as_immutable,
1425            Owner::Immutable => false,
1426            Owner::ObjectOwner(_) => {
1427                // protected by transaction input checker
1428                invariant_violation!("ObjectOwner objects cannot be input")
1429            }
1430        };
1431        let owner = obj.owner;
1432        let version = obj.version();
1433        let object_metadata = InputObjectMetadata::InputObject {
1434            id,
1435            is_mutable_input,
1436            owner,
1437            version,
1438        };
1439        let obj_value = value_from_object(vm, linkage_view, new_packages, obj)?;
1440        let contained_uids = {
1441            let fully_annotated_layout = vm
1442                .get_runtime()
1443                .type_to_fully_annotated_layout(&obj_value.type_)
1444                .map_err(|e| convert_vm_error(e, vm, linkage_view))?;
1445            let mut bytes = vec![];
1446            obj_value.write_bcs_bytes(&mut bytes, None)?;
1447            match get_all_uids(&fully_annotated_layout, &bytes) {
1448                Err(e) => {
1449                    invariant_violation!("Unable to retrieve UIDs for object. Got error: {e}")
1450                }
1451                Ok(uids) => uids,
1452            }
1453        };
1454        let runtime_input = object_runtime::InputObject {
1455            contained_uids,
1456            owner,
1457            version,
1458        };
1459        let prev = input_object_map.insert(id, runtime_input);
1460        // protected by transaction input checker
1461        assert_invariant!(prev.is_none(), "Duplicate input object {}", id);
1462        Ok(InputValue::new_object(object_metadata, obj_value))
1463    }
1464
1465    /// Load an a CallArg, either an object or a raw set of BCS bytes
1466    fn load_call_arg(
1467        vm: &MoveVM,
1468        state_view: &dyn ExecutionState,
1469        linkage_view: &mut LinkageView,
1470        new_packages: &[MovePackage],
1471        input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1472        call_arg: CallArg,
1473    ) -> Result<InputValue, ExecutionError> {
1474        Ok(match call_arg {
1475            CallArg::Pure(bytes) => InputValue::new_raw(RawValueType::Any, bytes),
1476            CallArg::Object(obj_arg) => load_object_arg(
1477                vm,
1478                state_view,
1479                linkage_view,
1480                new_packages,
1481                input_object_map,
1482                obj_arg,
1483            )?,
1484        })
1485    }
1486
1487    /// Load an ObjectArg from state view, marking if it can be treated as
1488    /// mutable or not
1489    fn load_object_arg(
1490        vm: &MoveVM,
1491        state_view: &dyn ExecutionState,
1492        linkage_view: &mut LinkageView,
1493        new_packages: &[MovePackage],
1494        input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1495        obj_arg: ObjectArg,
1496    ) -> Result<InputValue, ExecutionError> {
1497        match obj_arg {
1498            ObjectArg::ImmOrOwnedObject((id, _, _)) => load_object(
1499                vm,
1500                state_view,
1501                linkage_view,
1502                new_packages,
1503                input_object_map,
1504                // imm override
1505                false,
1506                id,
1507            ),
1508            ObjectArg::SharedObject { id, mutable, .. } => load_object(
1509                vm,
1510                state_view,
1511                linkage_view,
1512                new_packages,
1513                input_object_map,
1514                // imm override
1515                !mutable,
1516                id,
1517            ),
1518            ObjectArg::Receiving((id, version, _)) => {
1519                Ok(InputValue::new_receiving_object(id, version))
1520            }
1521        }
1522    }
1523
1524    /// Generate an additional write for an ObjectValue
1525    fn add_additional_write(
1526        additional_writes: &mut BTreeMap<ObjectID, AdditionalWrite>,
1527        owner: Owner,
1528        object_value: ObjectValue,
1529    ) -> Result<(), ExecutionError> {
1530        let ObjectValue {
1531            type_, contents, ..
1532        } = object_value;
1533        let bytes = match contents {
1534            ObjectContents::Coin(coin) => coin.to_bcs_bytes(),
1535            ObjectContents::Raw(bytes) => bytes,
1536        };
1537        let object_id = MoveObject::id_opt(&bytes).map_err(|e| {
1538            ExecutionError::invariant_violation(format!("No id for Raw object bytes. {e}"))
1539        })?;
1540        let additional_write = AdditionalWrite {
1541            recipient: owner,
1542            type_,
1543            bytes,
1544        };
1545        additional_writes.insert(object_id, additional_write);
1546        Ok(())
1547    }
1548
1549    /// The max budget was deducted from the gas coin at the beginning of the
1550    /// transaction, now we return exactly that amount. Gas will be charged
1551    /// by the execution engine
1552    fn refund_max_gas_budget(
1553        additional_writes: &mut BTreeMap<ObjectID, AdditionalWrite>,
1554        gas_charger: &mut GasCharger,
1555        gas_id: ObjectID,
1556    ) -> Result<(), ExecutionError> {
1557        let Some(AdditionalWrite { bytes, .. }) = additional_writes.get_mut(&gas_id) else {
1558            invariant_violation!("Gas object cannot be wrapped or destroyed")
1559        };
1560        let Ok(mut coin) = Coin::from_bcs_bytes(bytes) else {
1561            invariant_violation!("Gas object must be a coin")
1562        };
1563        let Some(new_balance) = coin.balance.value().checked_add(gas_charger.gas_budget()) else {
1564            return Err(ExecutionError::new_with_source(
1565                ExecutionErrorKind::CoinBalanceOverflow,
1566                "Gas coin too large after returning the max gas budget",
1567            ));
1568        };
1569        coin.balance = Balance::new(new_balance);
1570        *bytes = coin.to_bcs_bytes();
1571        Ok(())
1572    }
1573
1574    /// Generate an MoveObject given an updated/written object
1575    fn create_written_object(
1576        vm: &MoveVM,
1577        linkage_view: &LinkageView,
1578        protocol_config: &ProtocolConfig,
1579        objects_modified_at: &BTreeMap<ObjectID, LoadedRuntimeObject>,
1580        id: ObjectID,
1581        type_: Type,
1582        contents: Vec<u8>,
1583    ) -> Result<MoveObject, ExecutionError> {
1584        debug_assert_eq!(
1585            id,
1586            MoveObject::id_opt(&contents).expect("object contents should start with an id")
1587        );
1588        let old_obj_ver = objects_modified_at
1589            .get(&id)
1590            .map(|obj: &LoadedRuntimeObject| obj.version);
1591
1592        let type_tag = vm
1593            .get_runtime()
1594            .get_type_tag(&type_)
1595            .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1596
1597        let struct_tag = match type_tag {
1598            TypeTag::Struct(inner) => *inner,
1599            _ => invariant_violation!("Non struct type for object"),
1600        };
1601        MoveObject::new_from_execution(
1602            struct_tag.into(),
1603            old_obj_ver.unwrap_or_default(),
1604            contents,
1605            protocol_config,
1606        )
1607    }
1608
1609    // Implementation of the `DataStore` trait for the Move VM.
1610    // When used during execution it may have a list of new packages that have
1611    // just been published in the current context. Those are used for module/type
1612    // resolution when executing module init.
1613    // It may be created with an empty slice of packages either when no
1614    // publish/upgrade are performed or when a type is requested not during
1615    // execution.
1616    pub(crate) struct IotaDataStore<'state, 'a> {
1617        linkage_view: &'a LinkageView<'state>,
1618        new_packages: &'a [MovePackage],
1619    }
1620
1621    impl<'state, 'a> IotaDataStore<'state, 'a> {
1622        pub(crate) fn new(
1623            linkage_view: &'a LinkageView<'state>,
1624            new_packages: &'a [MovePackage],
1625        ) -> Self {
1626            Self {
1627                linkage_view,
1628                new_packages,
1629            }
1630        }
1631
1632        fn get_module(&self, module_id: &ModuleId) -> Option<&Vec<u8>> {
1633            for package in self.new_packages {
1634                let module = package.get_module(module_id);
1635                if module.is_some() {
1636                    return module;
1637                }
1638            }
1639            None
1640        }
1641    }
1642
1643    // TODO: `DataStore` will be reworked and this is likely to disappear.
1644    //       Leaving this comment around until then as testament to better days to
1645    // come...
1646    impl DataStore for IotaDataStore<'_, '_> {
1647        fn link_context(&self) -> AccountAddress {
1648            self.linkage_view.link_context()
1649        }
1650
1651        fn relocate(&self, module_id: &ModuleId) -> PartialVMResult<ModuleId> {
1652            self.linkage_view.relocate(module_id).map_err(|err| {
1653                PartialVMError::new(StatusCode::LINKER_ERROR)
1654                    .with_message(format!("Error relocating {module_id}: {err:?}"))
1655            })
1656        }
1657
1658        fn defining_module(
1659            &self,
1660            runtime_id: &ModuleId,
1661            struct_: &IdentStr,
1662        ) -> PartialVMResult<ModuleId> {
1663            self.linkage_view
1664                .defining_module(runtime_id, struct_)
1665                .map_err(|err| {
1666                    PartialVMError::new(StatusCode::LINKER_ERROR).with_message(format!(
1667                        "Error finding defining module for {runtime_id}::{struct_}: {err:?}"
1668                    ))
1669                })
1670        }
1671
1672        fn load_module(&self, module_id: &ModuleId) -> VMResult<Vec<u8>> {
1673            if let Some(bytes) = self.get_module(module_id) {
1674                return Ok(bytes.clone());
1675            }
1676            match self.linkage_view.get_module(module_id) {
1677                Ok(Some(bytes)) => Ok(bytes),
1678                Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1679                    .with_message(format!("Cannot find {module_id:?} in data cache"))
1680                    .finish(Location::Undefined)),
1681                Err(err) => {
1682                    let msg = format!("Unexpected storage error: {err:?}");
1683                    Err(
1684                        PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1685                            .with_message(msg)
1686                            .finish(Location::Undefined),
1687                    )
1688                }
1689            }
1690        }
1691
1692        fn publish_module(&mut self, _module_id: &ModuleId, _blob: Vec<u8>) -> VMResult<()> {
1693            // we cannot panic here because during execution and publishing this is
1694            // currently called from the publish flow in the Move runtime
1695            Ok(())
1696        }
1697    }
1698
1699    enum EitherError {
1700        CommandArgument(CommandArgumentError),
1701        Execution(ExecutionError),
1702    }
1703
1704    impl From<ExecutionError> for EitherError {
1705        fn from(e: ExecutionError) -> Self {
1706            EitherError::Execution(e)
1707        }
1708    }
1709
1710    impl From<CommandArgumentError> for EitherError {
1711        fn from(e: CommandArgumentError) -> Self {
1712            EitherError::CommandArgument(e)
1713        }
1714    }
1715
1716    impl EitherError {
1717        fn into_execution_error(self, command_index: usize) -> ExecutionError {
1718            match self {
1719                EitherError::CommandArgument(e) => command_argument_error(e, command_index),
1720                EitherError::Execution(e) => e,
1721            }
1722        }
1723    }
1724}