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