sui_adapter_v2/programmable_transactions/
execution.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4pub use checked::*;
5
6#[sui_macros::with_checked_arithmetic]
7mod checked {
8    use crate::execution_mode::ExecutionMode;
9    use crate::execution_value::{
10        CommandKind, ExecutionState, ObjectContents, ObjectValue, RawValueType, Value,
11    };
12    use crate::gas_charger::GasCharger;
13    use move_binary_format::{
14        compatibility::{Compatibility, InclusionCheck},
15        errors::{Location, PartialVMResult, VMResult},
16        file_format::{AbilitySet, CodeOffset, FunctionDefinitionIndex, LocalIndex, Visibility},
17        file_format_common::VERSION_6,
18        normalized, CompiledModule,
19    };
20    use move_core_types::{
21        account_address::AccountAddress,
22        identifier::{IdentStr, Identifier},
23        language_storage::{ModuleId, TypeTag},
24        u256::U256,
25    };
26    use move_vm_runtime::{
27        move_vm::MoveVM,
28        session::{LoadedFunctionInstantiation, SerializedReturnValues},
29    };
30    use move_vm_types::loaded_data::runtime_types::{CachedDatatype, Type};
31    use serde::{de::DeserializeSeed, Deserialize};
32    use std::{
33        collections::{BTreeMap, BTreeSet},
34        fmt,
35        sync::Arc,
36    };
37    use sui_move_natives::object_runtime::ObjectRuntime;
38    use sui_protocol_config::ProtocolConfig;
39    use sui_types::execution_status::{CommandArgumentError, PackageUpgradeError};
40    use sui_types::storage::{get_package_objects, PackageObject};
41    use sui_types::{
42        base_types::{
43            MoveLegacyTxContext, MoveObjectType, ObjectID, SuiAddress, TxContext, TxContextKind,
44            RESOLVED_ASCII_STR, RESOLVED_STD_OPTION, RESOLVED_UTF8_STR, TX_CONTEXT_MODULE_NAME,
45            TX_CONTEXT_STRUCT_NAME,
46        },
47        coin::Coin,
48        error::{command_argument_error, ExecutionError},
49        execution_status::ExecutionErrorKind,
50        id::RESOLVED_SUI_ID,
51        metrics::LimitsMetrics,
52        move_package::{
53            normalize_deserialized_modules, MovePackage, UpgradeCap, UpgradePolicy, UpgradeReceipt,
54            UpgradeTicket,
55        },
56        transaction::{Argument, Command, ProgrammableMoveCall, ProgrammableTransaction},
57        transfer::RESOLVED_RECEIVING_STRUCT,
58        SUI_FRAMEWORK_ADDRESS,
59    };
60    use sui_verifier::{
61        private_generics::{EVENT_MODULE, PRIVATE_TRANSFER_FUNCTIONS, TRANSFER_MODULE},
62        INIT_FN_NAME,
63    };
64    use tracing::instrument;
65
66    use crate::adapter::substitute_package_id;
67    use crate::programmable_transactions::context::*;
68
69    pub fn execute<Mode: ExecutionMode>(
70        protocol_config: &ProtocolConfig,
71        metrics: Arc<LimitsMetrics>,
72        vm: &MoveVM,
73        state_view: &mut dyn ExecutionState,
74        tx_context: &mut TxContext,
75        gas_charger: &mut GasCharger,
76        pt: ProgrammableTransaction,
77    ) -> Result<Mode::ExecutionResults, ExecutionError> {
78        let ProgrammableTransaction { inputs, commands } = pt;
79        let mut context = ExecutionContext::new(
80            protocol_config,
81            metrics,
82            vm,
83            state_view,
84            tx_context,
85            gas_charger,
86            inputs,
87        )?;
88        // execute commands
89        let mut mode_results = Mode::empty_results();
90        for (idx, command) in commands.into_iter().enumerate() {
91            if let Err(err) = execute_command::<Mode>(&mut context, &mut mode_results, command) {
92                let object_runtime: &ObjectRuntime = context.object_runtime();
93                // We still need to record the loaded child objects for replay
94                let loaded_runtime_objects = object_runtime.loaded_runtime_objects();
95                // we do not save the wrapped objects since on error, they should not be modified
96                drop(context);
97                state_view.save_loaded_runtime_objects(loaded_runtime_objects);
98                return Err(err.with_command_index(idx));
99            };
100        }
101
102        // Save loaded objects table in case we fail in post execution
103        let object_runtime: &ObjectRuntime = context.object_runtime();
104        // We still need to record the loaded child objects for replay
105        // Record the objects loaded at runtime (dynamic fields + received) for
106        // storage rebate calculation.
107        let loaded_runtime_objects = object_runtime.loaded_runtime_objects();
108        // We record what objects were contained in at the start of the transaction
109        // for expensive invariant checks
110        let wrapped_object_containers = object_runtime.wrapped_object_containers();
111
112        // apply changes
113        let finished = context.finish::<Mode>();
114        // Save loaded objects for debug. We dont want to lose the info
115        state_view.save_loaded_runtime_objects(loaded_runtime_objects);
116        state_view.save_wrapped_object_containers(wrapped_object_containers);
117        state_view.record_execution_results(finished?)?;
118        Ok(mode_results)
119    }
120
121    /// Execute a single command
122    #[instrument(level = "trace", skip_all)]
123    fn execute_command<Mode: ExecutionMode>(
124        context: &mut ExecutionContext<'_, '_, '_>,
125        mode_results: &mut Mode::ExecutionResults,
126        command: Command,
127    ) -> Result<(), ExecutionError> {
128        let mut argument_updates = Mode::empty_arguments();
129        let results = match command {
130            Command::MakeMoveVec(tag_opt, args) if args.is_empty() => {
131                let Some(tag) = tag_opt else {
132                    invariant_violation!(
133                        "input checker ensures if args are empty, there is a type specified"
134                    );
135                };
136
137                // SAFETY: Preserving existing behaviour for identifier deserialization within type
138                // tags and inputs.
139                let tag = unsafe { tag.into_type_tag_unchecked() };
140
141                let elem_ty = context
142                    .load_type(&tag)
143                    .map_err(|e| context.convert_vm_error(e))?;
144                let ty = Type::Vector(Box::new(elem_ty));
145                let abilities = context
146                    .vm
147                    .get_runtime()
148                    .get_type_abilities(&ty)
149                    .map_err(|e| context.convert_vm_error(e))?;
150                // BCS layout for any empty vector should be the same
151                let bytes = bcs::to_bytes::<Vec<u8>>(&vec![]).unwrap();
152                vec![Value::Raw(
153                    RawValueType::Loaded {
154                        ty,
155                        abilities,
156                        used_in_non_entry_move_call: false,
157                    },
158                    bytes,
159                )]
160            }
161            Command::MakeMoveVec(tag_opt, args) => {
162                let mut res = vec![];
163                leb128::write::unsigned(&mut res, args.len() as u64).unwrap();
164                let mut arg_iter = args.into_iter().enumerate();
165                let (mut used_in_non_entry_move_call, elem_ty) = match tag_opt {
166                    Some(tag) => {
167                        // SAFETY: Preserving existing behaviour for identifier deserialization within type
168                        // tags and inputs.
169                        let tag = unsafe { tag.into_type_tag_unchecked() };
170
171                        let elem_ty = context
172                            .load_type(&tag)
173                            .map_err(|e| context.convert_vm_error(e))?;
174                        (false, elem_ty)
175                    }
176                    // If no tag specified, it _must_ be an object
177                    None => {
178                        // empty args covered above
179                        let (idx, arg) = arg_iter.next().unwrap();
180                        let obj: ObjectValue =
181                            context.by_value_arg(CommandKind::MakeMoveVec, idx, arg)?;
182                        obj.write_bcs_bytes(&mut res);
183                        (obj.used_in_non_entry_move_call, obj.type_)
184                    }
185                };
186                for (idx, arg) in arg_iter {
187                    let value: Value = context.by_value_arg(CommandKind::MakeMoveVec, idx, arg)?;
188                    check_param_type::<Mode>(context, idx, &value, &elem_ty)?;
189                    used_in_non_entry_move_call =
190                        used_in_non_entry_move_call || value.was_used_in_non_entry_move_call();
191                    value.write_bcs_bytes(&mut res);
192                }
193                let ty = Type::Vector(Box::new(elem_ty));
194                let abilities = context
195                    .vm
196                    .get_runtime()
197                    .get_type_abilities(&ty)
198                    .map_err(|e| context.convert_vm_error(e))?;
199                vec![Value::Raw(
200                    RawValueType::Loaded {
201                        ty,
202                        abilities,
203                        used_in_non_entry_move_call,
204                    },
205                    res,
206                )]
207            }
208            Command::TransferObjects(objs, addr_arg) => {
209                let objs: Vec<ObjectValue> = objs
210                    .into_iter()
211                    .enumerate()
212                    .map(|(idx, arg)| context.by_value_arg(CommandKind::TransferObjects, idx, arg))
213                    .collect::<Result<_, _>>()?;
214                let addr: SuiAddress =
215                    context.by_value_arg(CommandKind::TransferObjects, objs.len(), addr_arg)?;
216                for obj in objs {
217                    obj.ensure_public_transfer_eligible()?;
218                    context.transfer_object(obj, addr)?;
219                }
220                vec![]
221            }
222            Command::SplitCoins(coin_arg, amount_args) => {
223                let mut obj: ObjectValue = context.borrow_arg_mut(0, coin_arg)?;
224                let ObjectContents::Coin(coin) = &mut obj.contents else {
225                    let e = ExecutionErrorKind::command_argument_error(
226                        CommandArgumentError::TypeMismatch,
227                        0,
228                    );
229                    let msg = "Expected a coin but got an non coin object".to_owned();
230                    return Err(ExecutionError::new_with_source(e, msg));
231                };
232                let split_coins = amount_args
233                    .into_iter()
234                    .map(|amount_arg| {
235                        let amount: u64 =
236                            context.by_value_arg(CommandKind::SplitCoins, 1, amount_arg)?;
237                        let new_coin_id = context.fresh_id()?;
238                        let new_coin = coin.split(amount, new_coin_id)?;
239                        let coin_type = obj.type_.clone();
240                        // safe because we are propagating the coin type, and relying on the internal
241                        // invariant that coin values have a coin type
242                        let new_coin = unsafe { ObjectValue::coin(coin_type, new_coin) };
243                        Ok(Value::Object(new_coin))
244                    })
245                    .collect::<Result<_, ExecutionError>>()?;
246                context.restore_arg::<Mode>(&mut argument_updates, coin_arg, Value::Object(obj))?;
247                split_coins
248            }
249            Command::MergeCoins(target_arg, coin_args) => {
250                let mut target: ObjectValue = context.borrow_arg_mut(0, target_arg)?;
251                let ObjectContents::Coin(target_coin) = &mut target.contents else {
252                    let e = ExecutionErrorKind::command_argument_error(
253                        CommandArgumentError::TypeMismatch,
254                        0,
255                    );
256                    let msg = "Expected a coin but got an non coin object".to_owned();
257                    return Err(ExecutionError::new_with_source(e, msg));
258                };
259                let coins: Vec<ObjectValue> = coin_args
260                    .into_iter()
261                    .enumerate()
262                    .map(|(idx, arg)| context.by_value_arg(CommandKind::MergeCoins, idx + 1, arg))
263                    .collect::<Result<_, _>>()?;
264                for (idx, coin) in coins.into_iter().enumerate() {
265                    if target.type_ != coin.type_ {
266                        let e = ExecutionErrorKind::command_argument_error(
267                            CommandArgumentError::TypeMismatch,
268                            (idx + 1) as u16,
269                        );
270                        let msg = "Coins do not have the same type".to_owned();
271                        return Err(ExecutionError::new_with_source(e, msg));
272                    }
273                    let ObjectContents::Coin(Coin { id, balance }) = coin.contents else {
274                        invariant_violation!(
275                            "Target coin was a coin, and we already checked for the same type. \
276                            This should be a coin"
277                        );
278                    };
279                    context.delete_id(*id.object_id())?;
280                    target_coin.add(balance)?;
281                }
282                context.restore_arg::<Mode>(
283                    &mut argument_updates,
284                    target_arg,
285                    Value::Object(target),
286                )?;
287                vec![]
288            }
289            Command::MoveCall(move_call) => {
290                let ProgrammableMoveCall {
291                    package,
292                    module,
293                    function,
294                    type_arguments,
295                    arguments,
296                } = *move_call;
297
298                // SAFETY: Preserving existing behaviour for identifier deserialization.
299                let module = unsafe { Identifier::new_unchecked(module) };
300                let function = unsafe { Identifier::new_unchecked(function) };
301
302                // Convert type arguments to `Type`s
303                let mut loaded_type_arguments = Vec::with_capacity(type_arguments.len());
304                for (ix, type_arg) in type_arguments.into_iter().enumerate() {
305                    // SAFETY: Preserving existing behaviour for identifier deserialization within type
306                    // tags and inputs.
307                    let type_arg = unsafe { type_arg.into_type_tag_unchecked() };
308
309                    let ty = context
310                        .load_type(&type_arg)
311                        .map_err(|e| context.convert_type_argument_error(ix, e))?;
312                    loaded_type_arguments.push(ty);
313                }
314
315                let original_address = context.set_link_context(package)?;
316                let runtime_id = ModuleId::new(original_address, module);
317                let return_values = execute_move_call::<Mode>(
318                    context,
319                    &mut argument_updates,
320                    &runtime_id,
321                    &function,
322                    loaded_type_arguments,
323                    arguments,
324                    /* is_init */ false,
325                );
326
327                context.linkage_view.reset_linkage();
328                return_values?
329            }
330            Command::Publish(modules, dep_ids) => {
331                execute_move_publish::<Mode>(context, &mut argument_updates, modules, dep_ids)?
332            }
333            Command::Upgrade(modules, dep_ids, current_package_id, upgrade_ticket) => {
334                execute_move_upgrade::<Mode>(
335                    context,
336                    modules,
337                    dep_ids,
338                    current_package_id,
339                    upgrade_ticket,
340                )?
341            }
342        };
343
344        Mode::finish_command(context, mode_results, argument_updates, &results)?;
345        context.push_command_results(results)?;
346        Ok(())
347    }
348
349    /// Execute a single Move call
350    fn execute_move_call<Mode: ExecutionMode>(
351        context: &mut ExecutionContext<'_, '_, '_>,
352        argument_updates: &mut Mode::ArgumentUpdates,
353        module_id: &ModuleId,
354        function: &IdentStr,
355        type_arguments: Vec<Type>,
356        arguments: Vec<Argument>,
357        is_init: bool,
358    ) -> Result<Vec<Value>, ExecutionError> {
359        // check that the function is either an entry function or a valid public function
360        let LoadedFunctionInfo {
361            kind,
362            signature,
363            return_value_kinds,
364            index,
365            last_instr,
366        } = check_visibility_and_signature::<Mode>(
367            context,
368            module_id,
369            function,
370            &type_arguments,
371            is_init,
372        )?;
373        // build the arguments, storing meta data about by-mut-ref args
374        let (tx_context_kind, by_mut_ref, serialized_arguments) =
375            build_move_args::<Mode>(context, module_id, function, kind, &signature, &arguments)?;
376        // invoke the VM
377        let SerializedReturnValues {
378            mutable_reference_outputs,
379            return_values,
380        } = vm_move_call(
381            context,
382            module_id,
383            function,
384            type_arguments,
385            tx_context_kind,
386            serialized_arguments,
387        )?;
388        assert_invariant!(
389            by_mut_ref.len() == mutable_reference_outputs.len(),
390            "lost mutable input"
391        );
392
393        context.take_user_events(module_id, index, last_instr)?;
394
395        // save the link context because calls to `make_value` below can set new ones, and we don't want
396        // it to be clobbered.
397        let saved_linkage = context.linkage_view.steal_linkage();
398        // write back mutable inputs. We also update if they were used in non entry Move calls
399        // though we do not care for immutable usages of objects or other values
400        let used_in_non_entry_move_call = kind == FunctionKind::NonEntry;
401        let res = write_back_results::<Mode>(
402            context,
403            argument_updates,
404            &arguments,
405            used_in_non_entry_move_call,
406            mutable_reference_outputs
407                .into_iter()
408                .map(|(i, bytes, _layout)| (i, bytes)),
409            by_mut_ref,
410            return_values.into_iter().map(|(bytes, _layout)| bytes),
411            return_value_kinds,
412        );
413
414        context.linkage_view.restore_linkage(saved_linkage)?;
415        res
416    }
417
418    fn write_back_results<Mode: ExecutionMode>(
419        context: &mut ExecutionContext<'_, '_, '_>,
420        argument_updates: &mut Mode::ArgumentUpdates,
421        arguments: &[Argument],
422        non_entry_move_call: bool,
423        mut_ref_values: impl IntoIterator<Item = (u8, Vec<u8>)>,
424        mut_ref_kinds: impl IntoIterator<Item = (u8, ValueKind)>,
425        return_values: impl IntoIterator<Item = Vec<u8>>,
426        return_value_kinds: impl IntoIterator<Item = ValueKind>,
427    ) -> Result<Vec<Value>, ExecutionError> {
428        for ((i, bytes), (j, kind)) in mut_ref_values.into_iter().zip(mut_ref_kinds) {
429            assert_invariant!(i == j, "lost mutable input");
430            let arg_idx = i as usize;
431            let value = make_value(context, kind, bytes, non_entry_move_call)?;
432            context.restore_arg::<Mode>(argument_updates, arguments[arg_idx], value)?;
433        }
434
435        return_values
436            .into_iter()
437            .zip(return_value_kinds)
438            .map(|(bytes, kind)| {
439                // only non entry functions have return values
440                make_value(
441                    context, kind, bytes, /* used_in_non_entry_move_call */ true,
442                )
443            })
444            .collect()
445    }
446
447    fn make_value(
448        context: &mut ExecutionContext<'_, '_, '_>,
449        value_info: ValueKind,
450        bytes: Vec<u8>,
451        used_in_non_entry_move_call: bool,
452    ) -> Result<Value, ExecutionError> {
453        Ok(match value_info {
454            ValueKind::Object {
455                type_,
456                has_public_transfer,
457            } => Value::Object(context.make_object_value(
458                type_,
459                has_public_transfer,
460                used_in_non_entry_move_call,
461                &bytes,
462            )?),
463            ValueKind::Raw(ty, abilities) => Value::Raw(
464                RawValueType::Loaded {
465                    ty,
466                    abilities,
467                    used_in_non_entry_move_call,
468                },
469                bytes,
470            ),
471        })
472    }
473
474    /// Publish Move modules and call the init functions.  Returns an `UpgradeCap` for the newly
475    /// published package on success.
476    fn execute_move_publish<Mode: ExecutionMode>(
477        context: &mut ExecutionContext<'_, '_, '_>,
478        argument_updates: &mut Mode::ArgumentUpdates,
479        module_bytes: Vec<Vec<u8>>,
480        dep_ids: Vec<ObjectID>,
481    ) -> Result<Vec<Value>, ExecutionError> {
482        assert_invariant!(
483            !module_bytes.is_empty(),
484            "empty package is checked in transaction input checker"
485        );
486        context
487            .gas_charger
488            .charge_publish_package(module_bytes.iter().map(|v| v.len()).sum())?;
489
490        let mut modules = deserialize_modules::<Mode>(context, &module_bytes)?;
491
492        // It should be fine that this does not go through ExecutionContext::fresh_id since the Move
493        // runtime does not to know about new packages created, since Move objects and Move packages
494        // cannot interact
495        let runtime_id = if Mode::packages_are_predefined() {
496            // do not calculate or substitute id for predefined packages
497            (*modules[0].self_id().address()).into()
498        } else {
499            let id = context.tx_context.fresh_id();
500            substitute_package_id(&mut modules, id)?;
501            id
502        };
503
504        // For newly published packages, runtime ID matches storage ID.
505        let storage_id = runtime_id;
506        let dependencies = fetch_packages(context, &dep_ids)?;
507        let package =
508            context.new_package(&modules, dependencies.iter().map(|p| p.move_package()))?;
509
510        // Here we optimistically push the package that is being published/upgraded
511        // and if there is an error of any kind (verification or module init) we
512        // remove it.
513        // The call to `pop_last_package` later is fine because we cannot re-enter and
514        // the last package we pushed is the one we are verifying and running the init from
515        context.linkage_view.set_linkage(&package)?;
516        context.write_package(package);
517        let res = publish_and_verify_modules(context, runtime_id, &modules)
518            .and_then(|_| init_modules::<Mode>(context, argument_updates, &modules));
519        context.linkage_view.reset_linkage();
520        if res.is_err() {
521            context.pop_package();
522        }
523        res?;
524
525        let values = if Mode::packages_are_predefined() {
526            // no upgrade cap for genesis modules
527            vec![]
528        } else {
529            let cap = &UpgradeCap::new(context.fresh_id()?, storage_id);
530            vec![Value::Object(context.make_object_value(
531                UpgradeCap::type_().into(),
532                /* has_public_transfer */ true,
533                /* used_in_non_entry_move_call */ false,
534                &bcs::to_bytes(cap).unwrap(),
535            )?)]
536        };
537        Ok(values)
538    }
539
540    /// Upgrade a Move package.  Returns an `UpgradeReceipt` for the upgraded package on success.
541    fn execute_move_upgrade<Mode: ExecutionMode>(
542        context: &mut ExecutionContext<'_, '_, '_>,
543        module_bytes: Vec<Vec<u8>>,
544        dep_ids: Vec<ObjectID>,
545        current_package_id: ObjectID,
546        upgrade_ticket_arg: Argument,
547    ) -> Result<Vec<Value>, ExecutionError> {
548        assert_invariant!(
549            !module_bytes.is_empty(),
550            "empty package is checked in transaction input checker"
551        );
552        context
553            .gas_charger
554            .charge_upgrade_package(module_bytes.iter().map(|v| v.len()).sum())?;
555
556        let upgrade_ticket_type = context
557            .load_type_from_struct(&UpgradeTicket::type_())
558            .map_err(|e| context.convert_vm_error(e))?;
559        let upgrade_receipt_type = context
560            .load_type_from_struct(&UpgradeReceipt::type_())
561            .map_err(|e| context.convert_vm_error(e))?;
562
563        let upgrade_ticket: UpgradeTicket = {
564            let mut ticket_bytes = Vec::new();
565            let ticket_val: Value =
566                context.by_value_arg(CommandKind::Upgrade, 0, upgrade_ticket_arg)?;
567            check_param_type::<Mode>(context, 0, &ticket_val, &upgrade_ticket_type)?;
568            ticket_val.write_bcs_bytes(&mut ticket_bytes);
569            bcs::from_bytes(&ticket_bytes).map_err(|_| {
570                ExecutionError::from_kind(ExecutionErrorKind::CommandArgumentError {
571                    arg_idx: 0,
572                    kind: CommandArgumentError::InvalidBCSBytes,
573                })
574            })?
575        };
576
577        // Make sure the passed-in package ID matches the package ID in the `upgrade_ticket`.
578        if current_package_id != upgrade_ticket.package.bytes {
579            return Err(ExecutionError::from_kind(
580                ExecutionErrorKind::PackageUpgradeError {
581                    upgrade_error: PackageUpgradeError::PackageIDDoesNotMatch {
582                        package_id: current_package_id,
583                        ticket_id: upgrade_ticket.package.bytes,
584                    },
585                },
586            ));
587        }
588
589        // Check digest.
590        let hash_modules = true;
591        let computed_digest =
592            MovePackage::compute_digest_for_modules_and_deps(&module_bytes, &dep_ids, hash_modules)
593                .to_vec();
594        if computed_digest != upgrade_ticket.digest {
595            return Err(ExecutionError::from_kind(
596                ExecutionErrorKind::PackageUpgradeError {
597                    upgrade_error: PackageUpgradeError::DigestDoesNotMatch {
598                        digest: computed_digest,
599                    },
600                },
601            ));
602        }
603
604        // Check that this package ID points to a package and get the package we're upgrading.
605        let current_package = fetch_package(context, &upgrade_ticket.package.bytes)?;
606
607        let mut modules = deserialize_modules::<Mode>(context, &module_bytes)?;
608        let runtime_id = current_package.move_package().original_package_id();
609        substitute_package_id(&mut modules, runtime_id)?;
610
611        // Upgraded packages share their predecessor's runtime ID but get a new storage ID.
612        let storage_id = context.tx_context.fresh_id();
613
614        let dependencies = fetch_packages(context, &dep_ids)?;
615        let package = context.upgrade_package(
616            storage_id,
617            current_package.move_package(),
618            &modules,
619            dependencies.iter().map(|p| p.move_package()),
620        )?;
621
622        context.linkage_view.set_linkage(&package)?;
623        let res = publish_and_verify_modules(context, runtime_id, &modules);
624        context.linkage_view.reset_linkage();
625        res?;
626
627        check_compatibility(
628            context,
629            current_package.move_package(),
630            &modules,
631            upgrade_ticket.policy,
632        )?;
633
634        context.write_package(package);
635        Ok(vec![Value::Raw(
636            RawValueType::Loaded {
637                ty: upgrade_receipt_type,
638                abilities: AbilitySet::EMPTY,
639                used_in_non_entry_move_call: false,
640            },
641            bcs::to_bytes(&UpgradeReceipt::new(upgrade_ticket, storage_id)).unwrap(),
642        )])
643    }
644
645    fn check_compatibility<'a>(
646        context: &ExecutionContext,
647        existing_package: &MovePackage,
648        upgrading_modules: impl IntoIterator<Item = &'a CompiledModule>,
649        policy: u8,
650    ) -> Result<(), ExecutionError> {
651        // Make sure this is a known upgrade policy.
652        let Ok(policy) = UpgradePolicy::try_from(policy) else {
653            return Err(ExecutionError::from_kind(
654                ExecutionErrorKind::PackageUpgradeError {
655                    upgrade_error: PackageUpgradeError::UnknownUpgradePolicy { policy },
656                },
657            ));
658        };
659
660        let pool = &mut normalized::RcPool::new();
661        let binary_config = context.protocol_config.binary_config(None);
662        let Ok(current_normalized) =
663            existing_package.normalize(pool, &binary_config, /* include code */ true)
664        else {
665            invariant_violation!("Tried to normalize modules in existing package but failed")
666        };
667
668        let mut new_normalized = normalize_deserialized_modules(
669            pool,
670            upgrading_modules.into_iter(),
671            /* include code */ true,
672        );
673        for (name, cur_module) in current_normalized {
674            let Some(new_module) = new_normalized.remove(&name) else {
675                return Err(ExecutionError::new_with_source(
676                    ExecutionErrorKind::PackageUpgradeError {
677                        upgrade_error: PackageUpgradeError::IncompatibleUpgrade,
678                    },
679                    format!("Existing module {name} not found in next version of package"),
680                ));
681            };
682
683            check_module_compatibility(&policy, &cur_module, &new_module)?;
684        }
685
686        Ok(())
687    }
688
689    fn check_module_compatibility(
690        policy: &UpgradePolicy,
691        cur_module: &move_binary_format::compatibility::Module,
692        new_module: &move_binary_format::compatibility::Module,
693    ) -> Result<(), ExecutionError> {
694        match policy {
695            UpgradePolicy::Additive => InclusionCheck::Subset.check(cur_module, new_module),
696            UpgradePolicy::DepOnly => InclusionCheck::Equal.check(cur_module, new_module),
697            UpgradePolicy::Compatible => {
698                let compatibility = Compatibility::upgrade_check();
699
700                compatibility.check(cur_module, new_module)
701            }
702        }
703        .map_err(|e| {
704            ExecutionError::new_with_source(
705                ExecutionErrorKind::PackageUpgradeError {
706                    upgrade_error: PackageUpgradeError::IncompatibleUpgrade,
707                },
708                e,
709            )
710        })
711    }
712
713    fn fetch_package(
714        context: &ExecutionContext<'_, '_, '_>,
715        package_id: &ObjectID,
716    ) -> Result<PackageObject, ExecutionError> {
717        let mut fetched_packages = fetch_packages(context, vec![package_id])?;
718        assert_invariant!(
719            fetched_packages.len() == 1,
720            "Number of fetched packages must match the number of package object IDs if successful."
721        );
722        match fetched_packages.pop() {
723            Some(pkg) => Ok(pkg),
724            None => invariant_violation!(
725                "We should always fetch a package for each object or return a dependency error."
726            ),
727        }
728    }
729
730    fn fetch_packages<'ctx, 'vm, 'state, 'a>(
731        context: &'ctx ExecutionContext<'vm, 'state, 'a>,
732        package_ids: impl IntoIterator<Item = &'ctx ObjectID>,
733    ) -> Result<Vec<PackageObject>, ExecutionError> {
734        let package_ids: BTreeSet<_> = package_ids.into_iter().collect();
735        match get_package_objects(&context.state_view, package_ids) {
736            Err(e) => Err(ExecutionError::new_with_source(
737                ExecutionErrorKind::PublishUpgradeMissingDependency,
738                e,
739            )),
740            Ok(Err(missing_deps)) => {
741                let msg = format!(
742                    "Missing dependencies: {}",
743                    missing_deps
744                        .into_iter()
745                        .map(|dep| format!("{}", dep))
746                        .collect::<Vec<_>>()
747                        .join(", ")
748                );
749                Err(ExecutionError::new_with_source(
750                    ExecutionErrorKind::PublishUpgradeMissingDependency,
751                    msg,
752                ))
753            }
754            Ok(Ok(pkgs)) => Ok(pkgs),
755        }
756    }
757
758    /***************************************************************************************************
759     * Move execution
760     **************************************************************************************************/
761
762    fn vm_move_call(
763        context: &mut ExecutionContext<'_, '_, '_>,
764        module_id: &ModuleId,
765        function: &IdentStr,
766        type_arguments: Vec<Type>,
767        tx_context_kind: TxContextKind,
768        mut serialized_arguments: Vec<Vec<u8>>,
769    ) -> Result<SerializedReturnValues, ExecutionError> {
770        match tx_context_kind {
771            TxContextKind::None => (),
772            TxContextKind::Mutable | TxContextKind::Immutable => {
773                serialized_arguments.push(context.tx_context.to_bcs_legacy_context());
774            }
775        }
776        // script visibility checked manually for entry points
777        let mut result = context
778            .execute_function_bypass_visibility(
779                module_id,
780                function,
781                type_arguments,
782                serialized_arguments,
783            )
784            .map_err(|e| context.convert_vm_error(e))?;
785
786        // When this function is used during publishing, it
787        // may be executed several times, with objects being
788        // created in the Move VM in each Move call. In such
789        // case, we need to update TxContext value so that it
790        // reflects what happened each time we call into the
791        // Move VM (e.g. to account for the number of created
792        // objects).
793        if tx_context_kind == TxContextKind::Mutable {
794            let Some((_, ctx_bytes, _)) = result.mutable_reference_outputs.pop() else {
795                invariant_violation!("Missing TxContext in reference outputs");
796            };
797            let updated_ctx: MoveLegacyTxContext = bcs::from_bytes(&ctx_bytes).map_err(|e| {
798                ExecutionError::invariant_violation(format!(
799                    "Unable to deserialize TxContext bytes. {e}"
800                ))
801            })?;
802            context.tx_context.update_state(updated_ctx)?;
803        }
804        Ok(result)
805    }
806
807    #[allow(clippy::extra_unused_type_parameters)]
808    fn deserialize_modules<Mode: ExecutionMode>(
809        context: &mut ExecutionContext<'_, '_, '_>,
810        module_bytes: &[Vec<u8>],
811    ) -> Result<Vec<CompiledModule>, ExecutionError> {
812        let binary_config = context.protocol_config.binary_config(None);
813        let modules = module_bytes
814            .iter()
815            .map(|b| {
816                CompiledModule::deserialize_with_config(b, &binary_config)
817                    .map_err(|e| e.finish(Location::Undefined))
818            })
819            .collect::<VMResult<Vec<CompiledModule>>>()
820            .map_err(|e| context.convert_vm_error(e))?;
821
822        assert_invariant!(
823            !modules.is_empty(),
824            "input checker ensures package is not empty"
825        );
826
827        Ok(modules)
828    }
829
830    fn publish_and_verify_modules(
831        context: &mut ExecutionContext<'_, '_, '_>,
832        package_id: ObjectID,
833        modules: &[CompiledModule],
834    ) -> Result<(), ExecutionError> {
835        // TODO(https://github.com/MystenLabs/sui/issues/69): avoid this redundant serialization by exposing VM API that allows us to run the linker directly on `Vec<CompiledModule>`
836        let new_module_bytes: Vec<_> = modules
837            .iter()
838            .map(|m| {
839                let mut bytes = Vec::new();
840                m.serialize_with_version(VERSION_6, &mut bytes).unwrap();
841                bytes
842            })
843            .collect();
844        context
845            .publish_module_bundle(new_module_bytes, AccountAddress::from(package_id))
846            .map_err(|e| context.convert_vm_error(e))?;
847
848        // run the Sui verifier
849        for module in modules {
850            // Run Sui bytecode verifier, which runs some additional checks that assume the Move
851            // bytecode verifier has passed.
852            sui_verifier::verifier::sui_verify_module_unmetered(
853                module,
854                &BTreeMap::new(),
855                &context
856                    .protocol_config
857                    .verifier_config(/* signing_limits */ None),
858            )?;
859        }
860
861        Ok(())
862    }
863
864    fn init_modules<Mode: ExecutionMode>(
865        context: &mut ExecutionContext<'_, '_, '_>,
866        argument_updates: &mut Mode::ArgumentUpdates,
867        modules: &[CompiledModule],
868    ) -> Result<(), ExecutionError> {
869        let modules_to_init = modules.iter().filter_map(|module| {
870            for fdef in &module.function_defs {
871                let fhandle = module.function_handle_at(fdef.function);
872                let fname = module.identifier_at(fhandle.name);
873                if fname == INIT_FN_NAME {
874                    return Some(module.self_id());
875                }
876            }
877            None
878        });
879
880        for module_id in modules_to_init {
881            let return_values = execute_move_call::<Mode>(
882                context,
883                argument_updates,
884                &module_id,
885                INIT_FN_NAME,
886                vec![],
887                vec![],
888                /* is_init */ true,
889            )?;
890
891            assert_invariant!(
892                return_values.is_empty(),
893                "init should not have return values"
894            )
895        }
896
897        Ok(())
898    }
899
900    /***************************************************************************************************
901     * Move signatures
902     **************************************************************************************************/
903
904    /// Helper marking what function we are invoking
905    #[derive(PartialEq, Eq, Clone, Copy)]
906    enum FunctionKind {
907        PrivateEntry,
908        PublicEntry,
909        NonEntry,
910        Init,
911    }
912
913    /// Used to remember type information about a type when resolving the signature
914    enum ValueKind {
915        Object {
916            type_: MoveObjectType,
917            has_public_transfer: bool,
918        },
919        Raw(Type, AbilitySet),
920    }
921
922    struct LoadedFunctionInfo {
923        /// The kind of the function, e.g. public or private or init
924        kind: FunctionKind,
925        /// The signature information of the function
926        signature: LoadedFunctionInstantiation,
927        /// Object or type information for the return values
928        return_value_kinds: Vec<ValueKind>,
929        /// Definition index of the function
930        index: FunctionDefinitionIndex,
931        /// The length of the function used for setting error information, or 0 if native
932        last_instr: CodeOffset,
933    }
934
935    /// Checks that the function to be called is either
936    /// - an entry function
937    /// - a public function that does not return references
938    /// - module init (only internal usage)
939    fn check_visibility_and_signature<Mode: ExecutionMode>(
940        context: &mut ExecutionContext<'_, '_, '_>,
941        module_id: &ModuleId,
942        function: &IdentStr,
943        type_arguments: &[Type],
944        from_init: bool,
945    ) -> Result<LoadedFunctionInfo, ExecutionError> {
946        if from_init {
947            let result = context.load_function(module_id, function, type_arguments);
948            assert_invariant!(
949                result.is_ok(),
950                "The modules init should be able to be loaded"
951            );
952        }
953        let no_new_packages = vec![];
954        let data_store = SuiDataStore::new(&context.linkage_view, &no_new_packages);
955        let module = context
956            .vm
957            .get_runtime()
958            .load_module(module_id, &data_store)
959            .map_err(|e| context.convert_vm_error(e))?;
960        let Some((index, fdef)) = module
961            .function_defs
962            .iter()
963            .enumerate()
964            .find(|(_index, fdef)| {
965                module.identifier_at(module.function_handle_at(fdef.function).name) == function
966            })
967        else {
968            return Err(ExecutionError::new_with_source(
969                ExecutionErrorKind::FunctionNotFound,
970                format!(
971                    "Could not resolve function '{}' in module {}",
972                    function, &module_id,
973                ),
974            ));
975        };
976
977        // entry on init is now banned, so ban invoking it
978        if !from_init && function == INIT_FN_NAME && context.protocol_config.ban_entry_init() {
979            return Err(ExecutionError::new_with_source(
980                ExecutionErrorKind::NonEntryFunctionInvoked,
981                "Cannot call 'init'",
982            ));
983        }
984
985        let last_instr: CodeOffset = fdef
986            .code
987            .as_ref()
988            .map(|code| code.code.len() - 1)
989            .unwrap_or(0) as CodeOffset;
990        let function_kind = match (fdef.visibility, fdef.is_entry) {
991            (Visibility::Private | Visibility::Friend, true) => FunctionKind::PrivateEntry,
992            (Visibility::Public, true) => FunctionKind::PublicEntry,
993            (Visibility::Public, false) => FunctionKind::NonEntry,
994            (Visibility::Private, false) if from_init => {
995                assert_invariant!(
996                    function == INIT_FN_NAME,
997                    "module init specified non-init function"
998                );
999                FunctionKind::Init
1000            }
1001            (Visibility::Private | Visibility::Friend, false)
1002                if Mode::allow_arbitrary_function_calls() =>
1003            {
1004                FunctionKind::NonEntry
1005            }
1006            (Visibility::Private | Visibility::Friend, false) => {
1007                return Err(ExecutionError::new_with_source(
1008                    ExecutionErrorKind::NonEntryFunctionInvoked,
1009                    "Can only call `entry` or `public` functions",
1010                ));
1011            }
1012        };
1013        let signature = context
1014            .load_function(module_id, function, type_arguments)
1015            .map_err(|e| context.convert_vm_error(e))?;
1016        let signature =
1017            subst_signature(signature, type_arguments).map_err(|e| context.convert_vm_error(e))?;
1018        let return_value_kinds = match function_kind {
1019            FunctionKind::Init => {
1020                assert_invariant!(
1021                    signature.return_.is_empty(),
1022                    "init functions must have no return values"
1023                );
1024                vec![]
1025            }
1026            FunctionKind::PrivateEntry | FunctionKind::PublicEntry | FunctionKind::NonEntry => {
1027                check_non_entry_signature::<Mode>(context, module_id, function, &signature)?
1028            }
1029        };
1030        check_private_generics(context, module_id, function, type_arguments)?;
1031        Ok(LoadedFunctionInfo {
1032            kind: function_kind,
1033            signature,
1034            return_value_kinds,
1035            index: FunctionDefinitionIndex(index as u16),
1036            last_instr,
1037        })
1038    }
1039
1040    /// substitutes the type arguments into the parameter and return types
1041    fn subst_signature(
1042        signature: LoadedFunctionInstantiation,
1043        type_arguments: &[Type],
1044    ) -> VMResult<LoadedFunctionInstantiation> {
1045        let LoadedFunctionInstantiation {
1046            parameters,
1047            return_,
1048        } = signature;
1049        let parameters = parameters
1050            .into_iter()
1051            .map(|ty| ty.subst(type_arguments))
1052            .collect::<PartialVMResult<Vec<_>>>()
1053            .map_err(|err| err.finish(Location::Undefined))?;
1054        let return_ = return_
1055            .into_iter()
1056            .map(|ty| ty.subst(type_arguments))
1057            .collect::<PartialVMResult<Vec<_>>>()
1058            .map_err(|err| err.finish(Location::Undefined))?;
1059        Ok(LoadedFunctionInstantiation {
1060            parameters,
1061            return_,
1062        })
1063    }
1064
1065    /// Checks that the non-entry function does not return references. And marks the return values
1066    /// as object or non-object return values
1067    fn check_non_entry_signature<Mode: ExecutionMode>(
1068        context: &mut ExecutionContext<'_, '_, '_>,
1069        _module_id: &ModuleId,
1070        _function: &IdentStr,
1071        signature: &LoadedFunctionInstantiation,
1072    ) -> Result<Vec<ValueKind>, ExecutionError> {
1073        signature
1074            .return_
1075            .iter()
1076            .enumerate()
1077            .map(|(idx, return_type)| {
1078                let return_type = match return_type {
1079                    // for dev-inspect, just dereference the value
1080                    Type::Reference(inner) | Type::MutableReference(inner)
1081                        if Mode::allow_arbitrary_values() =>
1082                    {
1083                        inner
1084                    }
1085                    Type::Reference(_) | Type::MutableReference(_) => {
1086                        return Err(ExecutionError::from_kind(
1087                            ExecutionErrorKind::InvalidPublicFunctionReturnType { idx: idx as u16 },
1088                        ))
1089                    }
1090                    t => t,
1091                };
1092                let abilities = context
1093                    .vm
1094                    .get_runtime()
1095                    .get_type_abilities(return_type)
1096                    .map_err(|e| context.convert_vm_error(e))?;
1097                Ok(match return_type {
1098                    Type::MutableReference(_) | Type::Reference(_) => unreachable!(),
1099                    Type::TyParam(_) => {
1100                        invariant_violation!("TyParam should have been substituted")
1101                    }
1102                    Type::Datatype(_) | Type::DatatypeInstantiation(_) if abilities.has_key() => {
1103                        let type_tag = context
1104                            .vm
1105                            .get_runtime()
1106                            .get_type_tag(return_type)
1107                            .map_err(|e| context.convert_vm_error(e))?;
1108                        let TypeTag::Struct(struct_tag) = type_tag else {
1109                            invariant_violation!("Struct type make a non struct type tag")
1110                        };
1111                        ValueKind::Object {
1112                            type_: MoveObjectType::from(*struct_tag),
1113                            has_public_transfer: abilities.has_store(),
1114                        }
1115                    }
1116                    Type::Datatype(_)
1117                    | Type::DatatypeInstantiation(_)
1118                    | Type::Bool
1119                    | Type::U8
1120                    | Type::U64
1121                    | Type::U128
1122                    | Type::Address
1123                    | Type::Signer
1124                    | Type::Vector(_)
1125                    | Type::U16
1126                    | Type::U32
1127                    | Type::U256 => ValueKind::Raw(return_type.clone(), abilities),
1128                })
1129            })
1130            .collect()
1131    }
1132
1133    fn check_private_generics(
1134        _context: &mut ExecutionContext,
1135        module_id: &ModuleId,
1136        function: &IdentStr,
1137        _type_arguments: &[Type],
1138    ) -> Result<(), ExecutionError> {
1139        let module_ident = (module_id.address(), module_id.name());
1140        if module_ident == (&SUI_FRAMEWORK_ADDRESS, EVENT_MODULE) {
1141            return Err(ExecutionError::new_with_source(
1142                ExecutionErrorKind::NonEntryFunctionInvoked,
1143                format!("Cannot directly call functions in sui::{}", EVENT_MODULE),
1144            ));
1145        }
1146
1147        if module_ident == (&SUI_FRAMEWORK_ADDRESS, TRANSFER_MODULE)
1148            && PRIVATE_TRANSFER_FUNCTIONS.contains(&function)
1149        {
1150            let msg = format!(
1151                "Cannot directly call sui::{m}::{f}. \
1152                Use the public variant instead, sui::{m}::public_{f}",
1153                m = TRANSFER_MODULE,
1154                f = function
1155            );
1156            return Err(ExecutionError::new_with_source(
1157                ExecutionErrorKind::NonEntryFunctionInvoked,
1158                msg,
1159            ));
1160        }
1161
1162        Ok(())
1163    }
1164
1165    type ArgInfo = (
1166        TxContextKind,
1167        /* mut ref */
1168        Vec<(LocalIndex, ValueKind)>,
1169        Vec<Vec<u8>>,
1170    );
1171
1172    /// Serializes the arguments into BCS values for Move. Performs the necessary type checking for
1173    /// each value
1174    fn build_move_args<Mode: ExecutionMode>(
1175        context: &mut ExecutionContext<'_, '_, '_>,
1176        module_id: &ModuleId,
1177        function: &IdentStr,
1178        function_kind: FunctionKind,
1179        signature: &LoadedFunctionInstantiation,
1180        args: &[Argument],
1181    ) -> Result<ArgInfo, ExecutionError> {
1182        // check the arity
1183        let parameters = &signature.parameters;
1184        let tx_ctx_kind = match parameters.last() {
1185            Some(t) => is_tx_context(context, t)?,
1186            None => TxContextKind::None,
1187        };
1188        // an init function can have one or two arguments, with the last one always being of type
1189        // &mut TxContext and the additional (first) one representing a one time witness type (see
1190        // one_time_witness verifier pass for additional explanation)
1191        let has_one_time_witness = function_kind == FunctionKind::Init && parameters.len() == 2;
1192        let has_tx_context = tx_ctx_kind != TxContextKind::None;
1193        let num_args = args.len() + (has_one_time_witness as usize) + (has_tx_context as usize);
1194        if num_args != parameters.len() {
1195            return Err(ExecutionError::new_with_source(
1196                ExecutionErrorKind::ArityMismatch,
1197                format!(
1198                    "Expected {:?} argument{} calling function '{}', but found {:?}",
1199                    parameters.len(),
1200                    if parameters.len() == 1 { "" } else { "s" },
1201                    function,
1202                    num_args
1203                ),
1204            ));
1205        }
1206
1207        // check the types and remember which are by mutable ref
1208        let mut by_mut_ref = vec![];
1209        let mut serialized_args = Vec::with_capacity(num_args);
1210        let command_kind = CommandKind::MoveCall {
1211            package: (*module_id.address()).into(),
1212            module: module_id.name(),
1213            function,
1214        };
1215        // an init function can have one or two arguments, with the last one always being of type
1216        // &mut TxContext and the additional (first) one representing a one time witness type (see
1217        // one_time_witness verifier pass for additional explanation)
1218        if has_one_time_witness {
1219            // one time witness type is a struct with a single bool filed which in bcs is encoded as
1220            // 0x01
1221            let bcs_true_value = bcs::to_bytes(&true).unwrap();
1222            serialized_args.push(bcs_true_value)
1223        }
1224        for ((idx, arg), param_ty) in args.iter().copied().enumerate().zip(parameters) {
1225            let (value, non_ref_param_ty): (Value, &Type) = match param_ty {
1226                Type::MutableReference(inner) => {
1227                    let value = context.borrow_arg_mut(idx, arg)?;
1228                    let object_info = if let Value::Object(ObjectValue {
1229                        type_,
1230                        has_public_transfer,
1231                        ..
1232                    }) = &value
1233                    {
1234                        let type_tag = context
1235                            .vm
1236                            .get_runtime()
1237                            .get_type_tag(type_)
1238                            .map_err(|e| context.convert_vm_error(e))?;
1239                        let TypeTag::Struct(struct_tag) = type_tag else {
1240                            invariant_violation!("Struct type make a non struct type tag")
1241                        };
1242                        let type_ = (*struct_tag).into();
1243                        ValueKind::Object {
1244                            type_,
1245                            has_public_transfer: *has_public_transfer,
1246                        }
1247                    } else {
1248                        let abilities = context
1249                            .vm
1250                            .get_runtime()
1251                            .get_type_abilities(inner)
1252                            .map_err(|e| context.convert_vm_error(e))?;
1253                        ValueKind::Raw((**inner).clone(), abilities)
1254                    };
1255                    by_mut_ref.push((idx as LocalIndex, object_info));
1256                    (value, inner)
1257                }
1258                Type::Reference(inner) => (context.borrow_arg(idx, arg, param_ty)?, inner),
1259                t => {
1260                    let value = context.by_value_arg(command_kind, idx, arg)?;
1261                    (value, t)
1262                }
1263            };
1264            if matches!(
1265                function_kind,
1266                FunctionKind::PrivateEntry | FunctionKind::Init
1267            ) && value.was_used_in_non_entry_move_call()
1268            {
1269                return Err(command_argument_error(
1270                    CommandArgumentError::InvalidArgumentToPrivateEntryFunction,
1271                    idx,
1272                ));
1273            }
1274            check_param_type::<Mode>(context, idx, &value, non_ref_param_ty)?;
1275            let bytes = {
1276                let mut v = vec![];
1277                value.write_bcs_bytes(&mut v);
1278                v
1279            };
1280            serialized_args.push(bytes);
1281        }
1282        Ok((tx_ctx_kind, by_mut_ref, serialized_args))
1283    }
1284
1285    /// checks that the value is compatible with the specified type
1286    fn check_param_type<Mode: ExecutionMode>(
1287        context: &mut ExecutionContext<'_, '_, '_>,
1288        idx: usize,
1289        value: &Value,
1290        param_ty: &Type,
1291    ) -> Result<(), ExecutionError> {
1292        match value {
1293            // For dev-spect, allow any BCS bytes. This does mean internal invariants for types can
1294            // be violated (like for string or Option)
1295            Value::Raw(RawValueType::Any, _) if Mode::allow_arbitrary_values() => return Ok(()),
1296            // Any means this was just some bytes passed in as an argument (as opposed to being
1297            // generated from a Move function). Meaning we only allow "primitive" values
1298            // and might need to run validation in addition to the BCS layout
1299            Value::Raw(RawValueType::Any, bytes) => {
1300                let Some(layout) = primitive_serialization_layout(context, param_ty)? else {
1301                    let msg = format!(
1302                        "Non-primitive argument at index {}. If it is an object, it must be \
1303                        populated by an object",
1304                        idx,
1305                    );
1306                    return Err(ExecutionError::new_with_source(
1307                        ExecutionErrorKind::command_argument_error(
1308                            CommandArgumentError::InvalidUsageOfPureArg,
1309                            idx as u16,
1310                        ),
1311                        msg,
1312                    ));
1313                };
1314                bcs_argument_validate(bytes, idx as u16, layout)?;
1315                return Ok(());
1316            }
1317            Value::Raw(RawValueType::Loaded { ty, abilities, .. }, _) => {
1318                assert_invariant!(
1319                    Mode::allow_arbitrary_values() || !abilities.has_key(),
1320                    "Raw value should never be an object"
1321                );
1322                if ty != param_ty {
1323                    return Err(command_argument_error(
1324                        CommandArgumentError::TypeMismatch,
1325                        idx,
1326                    ));
1327                }
1328            }
1329            Value::Object(obj) => {
1330                let ty = &obj.type_;
1331                if ty != param_ty {
1332                    return Err(command_argument_error(
1333                        CommandArgumentError::TypeMismatch,
1334                        idx,
1335                    ));
1336                }
1337            }
1338            Value::Receiving(_, _, assigned_type) => {
1339                // If the type has been fixed, make sure the types match up
1340                if let Some(assigned_type) = assigned_type {
1341                    if assigned_type != param_ty {
1342                        return Err(command_argument_error(
1343                            CommandArgumentError::TypeMismatch,
1344                            idx,
1345                        ));
1346                    }
1347                }
1348
1349                // Now make sure the param type is a struct instantiation of the receiving struct
1350                let Type::DatatypeInstantiation(struct_inst) = param_ty else {
1351                    return Err(command_argument_error(
1352                        CommandArgumentError::TypeMismatch,
1353                        idx,
1354                    ));
1355                };
1356                let (sidx, targs) = &**struct_inst;
1357                let Some(s) = context.vm.get_runtime().get_struct_type(*sidx) else {
1358                    invariant_violation!("sui::transfer::Receiving struct not found in session")
1359                };
1360                let resolved_struct = get_datatype_ident(&s);
1361
1362                if resolved_struct != RESOLVED_RECEIVING_STRUCT || targs.len() != 1 {
1363                    return Err(command_argument_error(
1364                        CommandArgumentError::TypeMismatch,
1365                        idx,
1366                    ));
1367                }
1368            }
1369        }
1370        Ok(())
1371    }
1372
1373    fn get_datatype_ident(s: &CachedDatatype) -> (&AccountAddress, &IdentStr, &IdentStr) {
1374        let module_id = &s.defining_id;
1375        let struct_name = &s.name;
1376        (
1377            module_id.address(),
1378            module_id.name(),
1379            struct_name.as_ident_str(),
1380        )
1381    }
1382
1383    // Returns Some(kind) if the type is a reference to the TxnContext. kind being Mutable with
1384    // a MutableReference, and Immutable otherwise.
1385    // Returns None for all other types
1386    pub fn is_tx_context(
1387        context: &mut ExecutionContext<'_, '_, '_>,
1388        t: &Type,
1389    ) -> Result<TxContextKind, ExecutionError> {
1390        let (is_mut, inner) = match t {
1391            Type::MutableReference(inner) => (true, inner),
1392            Type::Reference(inner) => (false, inner),
1393            _ => return Ok(TxContextKind::None),
1394        };
1395        let Type::Datatype(idx) = &**inner else {
1396            return Ok(TxContextKind::None);
1397        };
1398        let Some(s) = context.vm.get_runtime().get_struct_type(*idx) else {
1399            invariant_violation!("Loaded struct not found")
1400        };
1401        let (module_addr, module_name, struct_name) = get_datatype_ident(&s);
1402        let is_tx_context_type = module_addr == &SUI_FRAMEWORK_ADDRESS
1403            && module_name == TX_CONTEXT_MODULE_NAME
1404            && struct_name == TX_CONTEXT_STRUCT_NAME;
1405        Ok(if is_tx_context_type {
1406            if is_mut {
1407                TxContextKind::Mutable
1408            } else {
1409                TxContextKind::Immutable
1410            }
1411        } else {
1412            TxContextKind::None
1413        })
1414    }
1415
1416    /// Returns Some(layout) iff it is a primitive, an ID, a String, or an option/vector of a valid type
1417    fn primitive_serialization_layout(
1418        context: &mut ExecutionContext<'_, '_, '_>,
1419        param_ty: &Type,
1420    ) -> Result<Option<PrimitiveArgumentLayout>, ExecutionError> {
1421        Ok(match param_ty {
1422            Type::Signer => return Ok(None),
1423            Type::Reference(_) | Type::MutableReference(_) | Type::TyParam(_) => {
1424                invariant_violation!("references and type parameters should be checked elsewhere")
1425            }
1426            Type::Bool => Some(PrimitiveArgumentLayout::Bool),
1427            Type::U8 => Some(PrimitiveArgumentLayout::U8),
1428            Type::U16 => Some(PrimitiveArgumentLayout::U16),
1429            Type::U32 => Some(PrimitiveArgumentLayout::U32),
1430            Type::U64 => Some(PrimitiveArgumentLayout::U64),
1431            Type::U128 => Some(PrimitiveArgumentLayout::U128),
1432            Type::U256 => Some(PrimitiveArgumentLayout::U256),
1433            Type::Address => Some(PrimitiveArgumentLayout::Address),
1434
1435            Type::Vector(inner) => {
1436                let info_opt = primitive_serialization_layout(context, inner)?;
1437                info_opt.map(|layout| PrimitiveArgumentLayout::Vector(Box::new(layout)))
1438            }
1439            Type::DatatypeInstantiation(struct_inst) => {
1440                let (idx, targs) = &**struct_inst;
1441                let Some(s) = context.vm.get_runtime().get_struct_type(*idx) else {
1442                    invariant_violation!("Loaded struct not found")
1443                };
1444                let resolved_struct = get_datatype_ident(&s);
1445                // is option of a string
1446                if resolved_struct == RESOLVED_STD_OPTION && targs.len() == 1 {
1447                    let info_opt = primitive_serialization_layout(context, &targs[0])?;
1448                    info_opt.map(|layout| PrimitiveArgumentLayout::Option(Box::new(layout)))
1449                } else {
1450                    None
1451                }
1452            }
1453            Type::Datatype(idx) => {
1454                let Some(s) = context.vm.get_runtime().get_struct_type(*idx) else {
1455                    invariant_violation!("Loaded struct not found")
1456                };
1457                let resolved_struct = get_datatype_ident(&s);
1458                if resolved_struct == RESOLVED_SUI_ID {
1459                    Some(PrimitiveArgumentLayout::Address)
1460                } else if resolved_struct == RESOLVED_ASCII_STR {
1461                    Some(PrimitiveArgumentLayout::Ascii)
1462                } else if resolved_struct == RESOLVED_UTF8_STR {
1463                    Some(PrimitiveArgumentLayout::UTF8)
1464                } else {
1465                    None
1466                }
1467            }
1468        })
1469    }
1470
1471    /***************************************************************************************************
1472     * Special serialization formats
1473     **************************************************************************************************/
1474
1475    /// Special enum for values that need additional validation, in other words
1476    /// There is validation to do on top of the BCS layout. Currently only needed for
1477    /// strings
1478    #[derive(Debug)]
1479    pub enum PrimitiveArgumentLayout {
1480        /// An option
1481        Option(Box<PrimitiveArgumentLayout>),
1482        /// A vector
1483        Vector(Box<PrimitiveArgumentLayout>),
1484        /// An ASCII encoded string
1485        Ascii,
1486        /// A UTF8 encoded string
1487        UTF8,
1488        // needed for Option validation
1489        Bool,
1490        U8,
1491        U16,
1492        U32,
1493        U64,
1494        U128,
1495        U256,
1496        Address,
1497    }
1498
1499    impl PrimitiveArgumentLayout {
1500        /// returns true iff all BCS compatible bytes are actually values for this type.
1501        /// For example, this function returns false for Option and Strings since they need additional
1502        /// validation.
1503        pub fn bcs_only(&self) -> bool {
1504            match self {
1505                // have additional restrictions past BCS
1506                PrimitiveArgumentLayout::Option(_)
1507                | PrimitiveArgumentLayout::Ascii
1508                | PrimitiveArgumentLayout::UTF8 => false,
1509                // Move primitives are BCS compatible and do not need additional validation
1510                PrimitiveArgumentLayout::Bool
1511                | PrimitiveArgumentLayout::U8
1512                | PrimitiveArgumentLayout::U16
1513                | PrimitiveArgumentLayout::U32
1514                | PrimitiveArgumentLayout::U64
1515                | PrimitiveArgumentLayout::U128
1516                | PrimitiveArgumentLayout::U256
1517                | PrimitiveArgumentLayout::Address => true,
1518                // vector only needs validation if it's inner type does
1519                PrimitiveArgumentLayout::Vector(inner) => inner.bcs_only(),
1520            }
1521        }
1522    }
1523
1524    /// Checks the bytes against the `SpecialArgumentLayout` using `bcs`. It does not actually generate
1525    /// the deserialized value, only walks the bytes. While not necessary if the layout does not contain
1526    /// special arguments (e.g. Option or String) we check the BCS bytes for predictability
1527    pub fn bcs_argument_validate(
1528        bytes: &[u8],
1529        idx: u16,
1530        layout: PrimitiveArgumentLayout,
1531    ) -> Result<(), ExecutionError> {
1532        bcs::from_bytes_seed(&layout, bytes).map_err(|_| {
1533            ExecutionError::new_with_source(
1534                ExecutionErrorKind::command_argument_error(
1535                    CommandArgumentError::InvalidBCSBytes,
1536                    idx,
1537                ),
1538                format!("Function expects {layout} but provided argument's value does not match",),
1539            )
1540        })
1541    }
1542
1543    impl<'d> serde::de::DeserializeSeed<'d> for &PrimitiveArgumentLayout {
1544        type Value = ();
1545        fn deserialize<D: serde::de::Deserializer<'d>>(
1546            self,
1547            deserializer: D,
1548        ) -> Result<Self::Value, D::Error> {
1549            use serde::de::Error;
1550            match self {
1551                PrimitiveArgumentLayout::Ascii => {
1552                    let s: &str = serde::Deserialize::deserialize(deserializer)?;
1553                    if !s.is_ascii() {
1554                        Err(D::Error::custom("not an ascii string"))
1555                    } else {
1556                        Ok(())
1557                    }
1558                }
1559                PrimitiveArgumentLayout::UTF8 => {
1560                    deserializer.deserialize_string(serde::de::IgnoredAny)?;
1561                    Ok(())
1562                }
1563                PrimitiveArgumentLayout::Option(layout) => {
1564                    deserializer.deserialize_option(OptionElementVisitor(layout))
1565                }
1566                PrimitiveArgumentLayout::Vector(layout) => {
1567                    deserializer.deserialize_seq(VectorElementVisitor(layout))
1568                }
1569                // primitive move value cases, which are hit to make sure the correct number of bytes
1570                // are removed for elements of an option/vector
1571                PrimitiveArgumentLayout::Bool => {
1572                    deserializer.deserialize_bool(serde::de::IgnoredAny)?;
1573                    Ok(())
1574                }
1575                PrimitiveArgumentLayout::U8 => {
1576                    deserializer.deserialize_u8(serde::de::IgnoredAny)?;
1577                    Ok(())
1578                }
1579                PrimitiveArgumentLayout::U16 => {
1580                    deserializer.deserialize_u16(serde::de::IgnoredAny)?;
1581                    Ok(())
1582                }
1583                PrimitiveArgumentLayout::U32 => {
1584                    deserializer.deserialize_u32(serde::de::IgnoredAny)?;
1585                    Ok(())
1586                }
1587                PrimitiveArgumentLayout::U64 => {
1588                    deserializer.deserialize_u64(serde::de::IgnoredAny)?;
1589                    Ok(())
1590                }
1591                PrimitiveArgumentLayout::U128 => {
1592                    deserializer.deserialize_u128(serde::de::IgnoredAny)?;
1593                    Ok(())
1594                }
1595                PrimitiveArgumentLayout::U256 => {
1596                    U256::deserialize(deserializer)?;
1597                    Ok(())
1598                }
1599                PrimitiveArgumentLayout::Address => {
1600                    SuiAddress::deserialize(deserializer)?;
1601                    Ok(())
1602                }
1603            }
1604        }
1605    }
1606
1607    struct VectorElementVisitor<'a>(&'a PrimitiveArgumentLayout);
1608
1609    impl<'d> serde::de::Visitor<'d> for VectorElementVisitor<'_> {
1610        type Value = ();
1611
1612        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1613            formatter.write_str("Vector")
1614        }
1615
1616        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1617        where
1618            A: serde::de::SeqAccess<'d>,
1619        {
1620            while seq.next_element_seed(self.0)?.is_some() {}
1621            Ok(())
1622        }
1623    }
1624
1625    struct OptionElementVisitor<'a>(&'a PrimitiveArgumentLayout);
1626
1627    impl<'d> serde::de::Visitor<'d> for OptionElementVisitor<'_> {
1628        type Value = ();
1629
1630        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1631            formatter.write_str("Option")
1632        }
1633
1634        fn visit_none<E>(self) -> Result<Self::Value, E>
1635        where
1636            E: serde::de::Error,
1637        {
1638            Ok(())
1639        }
1640
1641        fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
1642        where
1643            D: serde::Deserializer<'d>,
1644        {
1645            self.0.deserialize(deserializer)
1646        }
1647    }
1648
1649    impl fmt::Display for PrimitiveArgumentLayout {
1650        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1651            match self {
1652                PrimitiveArgumentLayout::Vector(inner) => {
1653                    write!(f, "vector<{inner}>")
1654                }
1655                PrimitiveArgumentLayout::Option(inner) => {
1656                    write!(f, "std::option::Option<{inner}>")
1657                }
1658                PrimitiveArgumentLayout::Ascii => {
1659                    write!(f, "std::{}::{}", RESOLVED_ASCII_STR.1, RESOLVED_ASCII_STR.2)
1660                }
1661                PrimitiveArgumentLayout::UTF8 => {
1662                    write!(f, "std::{}::{}", RESOLVED_UTF8_STR.1, RESOLVED_UTF8_STR.2)
1663                }
1664                PrimitiveArgumentLayout::Bool => write!(f, "bool"),
1665                PrimitiveArgumentLayout::U8 => write!(f, "u8"),
1666                PrimitiveArgumentLayout::U16 => write!(f, "u16"),
1667                PrimitiveArgumentLayout::U32 => write!(f, "u32"),
1668                PrimitiveArgumentLayout::U64 => write!(f, "u64"),
1669                PrimitiveArgumentLayout::U128 => write!(f, "u128"),
1670                PrimitiveArgumentLayout::U256 => write!(f, "u256"),
1671                PrimitiveArgumentLayout::Address => write!(f, "address"),
1672            }
1673        }
1674    }
1675}