1pub use checked::*;
6
7#[iota_macros::with_checked_arithmetic]
8mod checked {
9 use std::{
10 borrow::Borrow,
11 collections::{BTreeMap, BTreeSet, HashMap},
12 sync::Arc,
13 };
14
15 use iota_move_natives::object_runtime::{
16 self, LoadedRuntimeObject, ObjectRuntime, RuntimeResults, get_all_uids, max_event_error,
17 };
18 use iota_protocol_config::ProtocolConfig;
19 use iota_types::{
20 balance::Balance,
21 base_types::{IotaAddress, MoveObjectType, ObjectID, TxContext},
22 coin::Coin,
23 error::{ExecutionError, ExecutionErrorKind, command_argument_error},
24 event::Event,
25 execution::{ExecutionResults, ExecutionResultsV1},
26 execution_status::CommandArgumentError,
27 metrics::LimitsMetrics,
28 move_package::MovePackage,
29 object::{Data, MoveObject, Object, ObjectInner, Owner},
30 storage::{BackingPackageStore, DenyListResult, PackageObject},
31 transaction::{Argument, CallArg, ObjectArg},
32 };
33 use move_binary_format::{
34 CompiledModule,
35 errors::{Location, PartialVMError, PartialVMResult, VMError, VMResult},
36 file_format::{CodeOffset, FunctionDefinitionIndex, TypeParameterIndex},
37 };
38 use move_core_types::{
39 account_address::AccountAddress,
40 identifier::IdentStr,
41 language_storage::{ModuleId, StructTag, TypeTag},
42 resolver::ModuleResolver,
43 vm_status::StatusCode,
44 };
45 use move_trace_format::format::MoveTraceBuilder;
46 use move_vm_runtime::{
47 move_vm::MoveVM,
48 native_extensions::NativeContextExtensions,
49 session::{LoadedFunctionInstantiation, SerializedReturnValues},
50 };
51 use move_vm_types::{data_store::DataStore, loaded_data::runtime_types::Type};
52 use tracing::instrument;
53
54 use crate::{
55 adapter::new_native_extensions,
56 error::convert_vm_error,
57 execution_mode::ExecutionMode,
58 execution_value::{
59 CommandKind, ExecutionState, InputObjectMetadata, InputValue, ObjectContents,
60 ObjectValue, RawValueType, ResultValue, TryFromValue, UsageKind, Value,
61 },
62 gas_charger::GasCharger,
63 programmable_transactions::linkage_view::LinkageView,
64 type_resolver::TypeTagResolver,
65 };
66
67 pub struct ExecutionContext<'vm, 'state, 'a> {
69 pub protocol_config: &'a ProtocolConfig,
71 pub metrics: Arc<LimitsMetrics>,
73 pub vm: &'vm MoveVM,
75 pub linkage_view: LinkageView<'state>,
77 pub native_extensions: NativeContextExtensions<'state>,
78 pub state_view: &'state dyn ExecutionState,
80 pub tx_context: &'a mut TxContext,
83 pub gas_charger: &'a mut GasCharger,
85 additional_transfers: Vec<(IotaAddress, ObjectValue)>,
87 new_packages: Vec<MovePackage>,
89 user_events: Vec<(ModuleId, StructTag, Vec<u8>)>,
91 gas: InputValue,
94 inputs: Vec<InputValue>,
97 results: Vec<Vec<ResultValue>>,
102 borrowed: HashMap<Argument, bool>,
106 }
107
108 struct AdditionalWrite {
111 recipient: Owner,
113 type_: Type,
115 bytes: Vec<u8>,
117 }
118
119 impl<'vm, 'state, 'a> ExecutionContext<'vm, 'state, 'a> {
120 #[instrument(name = "ExecutionContext::new", level = "trace", skip_all)]
127 pub fn new(
128 protocol_config: &'a ProtocolConfig,
129 metrics: Arc<LimitsMetrics>,
130 vm: &'vm MoveVM,
131 state_view: &'state dyn ExecutionState,
132 tx_context: &'a mut TxContext,
133 gas_charger: &'a mut GasCharger,
134 inputs: Vec<CallArg>,
135 ) -> Result<Self, ExecutionError>
136 where
137 'a: 'state,
138 {
139 let mut linkage_view = LinkageView::new(Box::new(state_view.as_iota_resolver()));
140 let mut input_object_map = BTreeMap::new();
141 let inputs = inputs
142 .into_iter()
143 .map(|call_arg| {
144 load_call_arg(
145 vm,
146 state_view,
147 &mut linkage_view,
148 &[],
149 &mut input_object_map,
150 call_arg,
151 )
152 })
153 .collect::<Result<_, ExecutionError>>()?;
154 let gas = if let Some(gas_coin) = gas_charger.gas_coin() {
155 let mut gas = load_object(
156 vm,
157 state_view,
158 &mut linkage_view,
159 &[],
160 &mut input_object_map,
161 false,
163 gas_coin,
164 )?;
165 let Some(Value::Object(ObjectValue {
169 contents: ObjectContents::Coin(coin),
170 ..
171 })) = &mut gas.inner.value
172 else {
173 invariant_violation!("Gas object should be a populated coin")
174 };
175
176 let max_gas_in_balance = gas_charger.gas_budget();
177 let Some(new_balance) = coin.balance.value().checked_sub(max_gas_in_balance) else {
178 invariant_violation!(
179 "Transaction input checker should check that there is enough gas"
180 );
181 };
182 coin.balance = Balance::new(new_balance);
183 gas
184 } else {
185 InputValue {
186 object_metadata: None,
187 inner: ResultValue {
188 last_usage_kind: None,
189 value: None,
190 },
191 }
192 };
193 let native_extensions = new_native_extensions(
194 state_view.as_child_resolver(),
195 input_object_map,
196 !gas_charger.is_unmetered(),
197 protocol_config,
198 metrics.clone(),
199 tx_context.epoch(),
200 );
201
202 #[skip_checked_arithmetic]
204 move_vm_profiler::tracing_feature_enabled! {
205 use move_vm_profiler::GasProfiler;
206 use move_vm_types::gas::GasMeter;
207
208 let tx_digest = tx_context.digest();
209 let remaining_gas: u64 =
210 move_vm_types::gas::GasMeter::remaining_gas(gas_charger.move_gas_status())
211 .into();
212 gas_charger
213 .move_gas_status_mut()
214 .set_profiler(GasProfiler::init(
215 &vm.config().profiler_config,
216 format!("{}", tx_digest),
217 remaining_gas,
218 ));
219 }
220
221 Ok(Self {
222 protocol_config,
223 metrics,
224 vm,
225 linkage_view,
226 native_extensions,
227 state_view,
228 tx_context,
229 gas_charger,
230 gas,
231 inputs,
232 results: vec![],
233 additional_transfers: vec![],
234 new_packages: vec![],
235 user_events: vec![],
236 borrowed: HashMap::new(),
237 })
238 }
239
240 pub fn object_runtime(&mut self) -> &ObjectRuntime {
241 self.native_extensions.get()
242 }
243
244 pub fn fresh_id(&mut self) -> Result<ObjectID, ExecutionError> {
246 let object_id = self.tx_context.fresh_id();
247 let object_runtime: &mut ObjectRuntime = self.native_extensions.get_mut();
248 object_runtime
249 .new_id(object_id)
250 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
251 Ok(object_id)
252 }
253
254 pub fn delete_id(&mut self, object_id: ObjectID) -> Result<(), ExecutionError> {
256 let object_runtime: &mut ObjectRuntime = self.native_extensions.get_mut();
257 object_runtime
258 .delete_id(object_id)
259 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))
260 }
261
262 pub fn set_link_context(
266 &mut self,
267 package_id: ObjectID,
268 ) -> Result<AccountAddress, ExecutionError> {
269 if self.linkage_view.has_linkage(package_id) {
270 return Ok(self
272 .linkage_view
273 .original_package_id()
274 .unwrap_or(*package_id));
275 }
276
277 let package = package_for_linkage(&self.linkage_view, package_id)
278 .map_err(|e| self.convert_vm_error(e))?;
279
280 self.linkage_view.set_linkage(package.move_package())
281 }
282
283 pub fn load_type(&mut self, type_tag: &TypeTag) -> VMResult<Type> {
285 load_type(
286 self.vm,
287 &mut self.linkage_view,
288 &self.new_packages,
289 type_tag,
290 )
291 }
292
293 pub fn load_type_from_struct(&mut self, struct_tag: &StructTag) -> VMResult<Type> {
295 load_type_from_struct(
296 self.vm,
297 &mut self.linkage_view,
298 &self.new_packages,
299 struct_tag,
300 )
301 }
302
303 pub fn take_user_events(
306 &mut self,
307 module_id: &ModuleId,
308 function: FunctionDefinitionIndex,
309 last_offset: CodeOffset,
310 ) -> Result<(), ExecutionError> {
311 let object_runtime: &mut ObjectRuntime = self.native_extensions.get_mut();
312 let events = object_runtime.take_user_events();
313 let num_events = self.user_events.len() + events.len();
314 let max_events = self.protocol_config.max_num_event_emit();
315 if num_events as u64 > max_events {
316 let err = max_event_error(max_events)
317 .at_code_offset(function, last_offset)
318 .finish(Location::Module(module_id.clone()));
319 return Err(self.convert_vm_error(err));
320 }
321 let new_events = events
322 .into_iter()
323 .map(|(ty, tag, value)| {
324 let layout = self
325 .vm
326 .get_runtime()
327 .type_to_type_layout(&ty)
328 .map_err(|e| self.convert_vm_error(e))?;
329 let Some(bytes) = value.simple_serialize(&layout) else {
330 invariant_violation!("Failed to deserialize already serialized Move value");
331 };
332 Ok((module_id.clone(), tag, bytes))
333 })
334 .collect::<Result<Vec<_>, ExecutionError>>()?;
335 self.user_events.extend(new_events);
336 Ok(())
337 }
338
339 pub fn by_value_arg<V: TryFromValue>(
345 &mut self,
346 command_kind: CommandKind<'_>,
347 arg_idx: usize,
348 arg: Argument,
349 ) -> Result<V, ExecutionError> {
350 self.by_value_arg_(command_kind, arg)
351 .map_err(|e| command_argument_error(e, arg_idx))
352 }
353 fn by_value_arg_<V: TryFromValue>(
354 &mut self,
355 command_kind: CommandKind<'_>,
356 arg: Argument,
357 ) -> Result<V, CommandArgumentError> {
358 let is_borrowed = self.arg_is_borrowed(&arg);
359 let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::ByValue)?;
360 let is_copyable = if let Some(val) = val_opt {
361 val.is_copyable()
362 } else {
363 return Err(CommandArgumentError::InvalidValueUsage);
364 };
365 if !is_copyable && is_borrowed {
371 return Err(CommandArgumentError::InvalidValueUsage);
372 }
373 if matches!(arg, Argument::GasCoin)
375 && !matches!(command_kind, CommandKind::TransferObjects)
376 {
377 return Err(CommandArgumentError::InvalidGasCoinUsage);
378 }
379 if matches!(
381 input_metadata_opt,
382 Some(InputObjectMetadata::InputObject {
383 owner: Owner::Immutable,
384 ..
385 })
386 ) {
387 return Err(CommandArgumentError::InvalidObjectByValue);
388 }
389
390 if matches!(
392 input_metadata_opt,
393 Some(InputObjectMetadata::InputObject {
394 is_mutable_input: false,
395 ..
396 })
397 ) {
398 return Err(CommandArgumentError::InvalidObjectByValue);
399 }
400
401 let val = if is_copyable {
402 val_opt.as_ref().unwrap().clone()
403 } else {
404 val_opt.take().unwrap()
405 };
406 V::try_from_value(val)
407 }
408
409 pub fn borrow_arg_mut<V: TryFromValue>(
416 &mut self,
417 arg_idx: usize,
418 arg: Argument,
419 ) -> Result<V, ExecutionError> {
420 self.borrow_arg_mut_(arg)
421 .map_err(|e| command_argument_error(e, arg_idx))
422 }
423 fn borrow_arg_mut_<V: TryFromValue>(
424 &mut self,
425 arg: Argument,
426 ) -> Result<V, CommandArgumentError> {
427 if self.arg_is_borrowed(&arg) {
429 return Err(CommandArgumentError::InvalidValueUsage);
430 }
431 self.borrowed.insert(arg, true);
432 let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowMut)?;
433 let is_copyable = if let Some(val) = val_opt {
434 val.is_copyable()
435 } else {
436 return Err(CommandArgumentError::InvalidValueUsage);
438 };
439 if let Some(InputObjectMetadata::InputObject {
440 is_mutable_input: false,
441 ..
442 }) = input_metadata_opt
443 {
444 return Err(CommandArgumentError::InvalidObjectByMutRef);
445 }
446 let val = if is_copyable {
449 val_opt.as_ref().unwrap().clone()
450 } else {
451 val_opt.take().unwrap()
452 };
453 V::try_from_value(val)
454 }
455
456 pub fn borrow_arg<V: TryFromValue>(
461 &mut self,
462 arg_idx: usize,
463 arg: Argument,
464 type_: &Type,
465 ) -> Result<V, ExecutionError> {
466 self.borrow_arg_(arg, type_)
467 .map_err(|e| command_argument_error(e, arg_idx))
468 }
469 fn borrow_arg_<V: TryFromValue>(
470 &mut self,
471 arg: Argument,
472 arg_type: &Type,
473 ) -> Result<V, CommandArgumentError> {
474 if self.arg_is_mut_borrowed(&arg) {
478 return Err(CommandArgumentError::InvalidValueUsage);
479 }
480 self.borrowed.insert(arg, false);
481 let (_input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowImm)?;
482 if val_opt.is_none() {
483 return Err(CommandArgumentError::InvalidValueUsage);
484 }
485
486 if let &mut Some(Value::Receiving(_, _, ref mut recv_arg_type @ None)) = val_opt {
488 let Type::Reference(inner) = arg_type else {
489 return Err(CommandArgumentError::InvalidValueUsage);
490 };
491 *recv_arg_type = Some(*(*inner).clone());
492 }
493
494 V::try_from_value(val_opt.as_ref().unwrap().clone())
495 }
496
497 pub fn restore_arg<Mode: ExecutionMode>(
499 &mut self,
500 updates: &mut Mode::ArgumentUpdates,
501 arg: Argument,
502 value: Value,
503 ) -> Result<(), ExecutionError> {
504 Mode::add_argument_update(self, updates, arg, &value)?;
505 let was_mut_opt = self.borrowed.remove(&arg);
506 assert_invariant!(
507 was_mut_opt.is_some() && was_mut_opt.unwrap(),
508 "Should never restore a non-mut borrowed value. \
509 The take+restore is an implementation detail of mutable references"
510 );
511 let Ok((_, value_opt)) = self.borrow_mut_impl(arg, None) else {
513 invariant_violation!("Should be able to borrow argument to restore it")
514 };
515
516 let old_value = value_opt.replace(value);
517 assert_invariant!(
518 old_value.is_none() || old_value.unwrap().is_copyable(),
519 "Should never restore a non-taken value, unless it is copyable. \
520 The take+restore is an implementation detail of mutable references"
521 );
522
523 Ok(())
524 }
525
526 pub fn transfer_object(
528 &mut self,
529 obj: ObjectValue,
530 addr: IotaAddress,
531 ) -> Result<(), ExecutionError> {
532 self.additional_transfers.push((addr, obj));
533 Ok(())
534 }
535
536 pub fn new_package<'p>(
538 &self,
539 modules: &[CompiledModule],
540 dependencies: impl IntoIterator<Item = &'p MovePackage>,
541 ) -> Result<MovePackage, ExecutionError> {
542 MovePackage::new_initial(
543 modules,
544 self.protocol_config.max_move_package_size(),
545 self.protocol_config.move_binary_format_version(),
546 dependencies,
547 )
548 }
549
550 pub fn upgrade_package<'p>(
553 &self,
554 storage_id: ObjectID,
555 previous_package: &MovePackage,
556 new_modules: &[CompiledModule],
557 dependencies: impl IntoIterator<Item = &'p MovePackage>,
558 ) -> Result<MovePackage, ExecutionError> {
559 previous_package.new_upgraded(
560 storage_id,
561 new_modules,
562 self.protocol_config,
563 dependencies,
564 )
565 }
566
567 pub fn write_package(&mut self, package: MovePackage) {
569 self.new_packages.push(package);
570 }
571
572 pub fn pop_package(&mut self) -> Option<MovePackage> {
578 self.new_packages.pop()
579 }
580
581 pub fn push_command_results(&mut self, results: Vec<Value>) -> Result<(), ExecutionError> {
584 assert_invariant!(
585 self.borrowed.values().all(|is_mut| !is_mut),
586 "all mut borrows should be restored"
587 );
588 self.borrowed = HashMap::new();
590 self.results
591 .push(results.into_iter().map(ResultValue::new).collect());
592 Ok(())
593 }
594
595 pub fn finish<Mode: ExecutionMode>(self) -> Result<ExecutionResults, ExecutionError> {
597 let Self {
598 protocol_config,
599 vm,
600 linkage_view,
601 mut native_extensions,
602 tx_context,
603 gas_charger,
604 additional_transfers,
605 new_packages,
606 gas,
607 inputs,
608 results,
609 user_events,
610 state_view,
611 ..
612 } = self;
613 let tx_digest = tx_context.digest();
614 let gas_id_opt = gas.object_metadata.as_ref().map(|info| info.id());
615 let mut loaded_runtime_objects = BTreeMap::new();
616 let mut additional_writes = BTreeMap::new();
617 let mut by_value_shared_objects = BTreeSet::new();
618 for input in inputs.into_iter().chain(std::iter::once(gas)) {
619 let InputValue {
620 object_metadata:
621 Some(InputObjectMetadata::InputObject {
622 is_mutable_input: true,
624 id,
625 version,
626 owner,
627 }),
628 inner: ResultValue { value, .. },
629 } = input
630 else {
631 continue;
632 };
633 loaded_runtime_objects.insert(
634 id,
635 LoadedRuntimeObject {
636 version,
637 is_modified: true,
638 },
639 );
640 if let Some(Value::Object(object_value)) = value {
641 add_additional_write(&mut additional_writes, owner, object_value)?;
642 } else if owner.is_shared() {
643 by_value_shared_objects.insert(id);
644 }
645 }
646 if !Mode::allow_arbitrary_values() {
649 for (i, command_result) in results.iter().enumerate() {
650 for (j, result_value) in command_result.iter().enumerate() {
651 let ResultValue {
652 last_usage_kind,
653 value,
654 } = result_value;
655 match value {
656 None => (),
657 Some(Value::Object(_)) => {
658 return Err(ExecutionErrorKind::UnusedValueWithoutDrop {
659 result_idx: i as u16,
660 secondary_idx: j as u16,
661 }
662 .into());
663 }
664 Some(Value::Raw(RawValueType::Any, _)) => (),
665 Some(Value::Raw(RawValueType::Loaded { abilities, .. }, _)) => {
666 if abilities.has_drop()
672 || (abilities.has_copy()
673 && matches!(last_usage_kind, Some(UsageKind::ByValue)))
674 {
675 } else {
676 let msg = if abilities.has_copy() {
677 "The value has copy, but not drop. \
678 Its last usage must be by-value so it can be taken."
679 } else {
680 "Unused value without drop"
681 };
682 return Err(ExecutionError::new_with_source(
683 ExecutionErrorKind::UnusedValueWithoutDrop {
684 result_idx: i as u16,
685 secondary_idx: j as u16,
686 },
687 msg,
688 ));
689 }
690 }
691 Some(Value::Receiving(_, _, _)) => (),
693 }
694 }
695 }
696 }
697 for (recipient, object_value) in additional_transfers {
699 let owner = Owner::AddressOwner(recipient);
700 add_additional_write(&mut additional_writes, owner, object_value)?;
701 }
702 if let Some(gas_id) = gas_id_opt {
704 refund_max_gas_budget(&mut additional_writes, gas_charger, gas_id)?;
705 }
706
707 let object_runtime: ObjectRuntime = native_extensions.remove();
708
709 let RuntimeResults {
710 writes,
711 user_events: remaining_events,
712 loaded_child_objects,
713 mut created_object_ids,
714 deleted_object_ids,
715 } = object_runtime.finish()?;
716 assert_invariant!(
717 remaining_events.is_empty(),
718 "Events should be taken after every Move call"
719 );
720
721 loaded_runtime_objects.extend(loaded_child_objects);
722
723 let mut written_objects = BTreeMap::new();
724 for package in new_packages {
725 let package_obj = Object::new_from_package(package, tx_digest);
726 let id = package_obj.id();
727 created_object_ids.insert(id);
728 written_objects.insert(id, package_obj);
729 }
730 for (id, additional_write) in additional_writes {
731 let AdditionalWrite {
732 recipient,
733 type_,
734 bytes,
735 } = additional_write;
736
737 let move_object = {
738 create_written_object(
739 vm,
740 &linkage_view,
741 protocol_config,
742 &loaded_runtime_objects,
743 id,
744 type_,
745 bytes,
746 )?
747 };
748 let object = Object::new_move(move_object, recipient, tx_digest);
749 written_objects.insert(id, object);
750 if let Some(loaded) = loaded_runtime_objects.get_mut(&id) {
751 loaded.is_modified = true;
752 }
753 }
754
755 for (id, (recipient, ty, value)) in writes {
756 let layout = vm
757 .get_runtime()
758 .type_to_type_layout(&ty)
759 .map_err(|e| convert_vm_error(e, vm, &linkage_view))?;
760 let Some(bytes) = value.simple_serialize(&layout) else {
761 invariant_violation!("Failed to deserialize already serialized Move value");
762 };
763 let move_object = {
764 create_written_object(
765 vm,
766 &linkage_view,
767 protocol_config,
768 &loaded_runtime_objects,
769 id,
770 ty,
771 bytes,
772 )?
773 };
774 let object = Object::new_move(move_object, recipient, tx_digest);
775 written_objects.insert(id, object);
776 }
777
778 for id in &by_value_shared_objects {
785 if let Some(obj) = written_objects.get(id) {
788 if !obj.is_shared() {
789 return Err(ExecutionError::new(
790 ExecutionErrorKind::SharedObjectOperationNotAllowed,
791 Some(
792 format!(
793 "Shared object operation on {} not allowed: \
794 cannot be frozen, transferred, or wrapped",
795 id
796 )
797 .into(),
798 ),
799 ));
800 }
801 } else {
802 if !deleted_object_ids.contains(id) {
805 return Err(ExecutionError::new(
806 ExecutionErrorKind::SharedObjectOperationNotAllowed,
807 Some(
808 format!("Shared object operation on {} not allowed: \
809 shared objects used by value must be re-shared if not deleted", id).into(),
810 ),
811 ));
812 }
813 }
814 }
815
816 let DenyListResult {
817 result,
818 num_non_gas_coin_owners,
819 } = state_view.check_coin_deny_list(&written_objects);
820 gas_charger.charge_coin_transfers(protocol_config, num_non_gas_coin_owners)?;
821 result?;
822
823 let user_events = user_events
824 .into_iter()
825 .map(|(module_id, tag, contents)| {
826 Event::new(
827 module_id.address(),
828 module_id.name(),
829 tx_context.sender(),
830 tag,
831 contents,
832 )
833 })
834 .collect();
835
836 Ok(ExecutionResults::V1(ExecutionResultsV1 {
837 written_objects,
838 modified_objects: loaded_runtime_objects
839 .into_iter()
840 .filter_map(|(id, loaded)| loaded.is_modified.then_some(id))
841 .collect(),
842 created_object_ids: created_object_ids.into_iter().collect(),
843 deleted_object_ids: deleted_object_ids.into_iter().collect(),
844 user_events,
845 }))
846 }
847
848 pub fn convert_vm_error(&self, error: VMError) -> ExecutionError {
850 crate::error::convert_vm_error(error, self.vm, &self.linkage_view)
851 }
852
853 pub fn convert_type_argument_error(&self, idx: usize, error: VMError) -> ExecutionError {
855 use iota_types::execution_status::TypeArgumentError;
856 use move_core_types::vm_status::StatusCode;
857 match error.major_status() {
858 StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
859 ExecutionErrorKind::TypeArityMismatch.into()
860 }
861 StatusCode::TYPE_RESOLUTION_FAILURE => ExecutionErrorKind::TypeArgumentError {
862 argument_idx: idx as TypeParameterIndex,
863 kind: TypeArgumentError::TypeNotFound,
864 }
865 .into(),
866 StatusCode::CONSTRAINT_NOT_SATISFIED => ExecutionErrorKind::TypeArgumentError {
867 argument_idx: idx as TypeParameterIndex,
868 kind: TypeArgumentError::ConstraintNotSatisfied,
869 }
870 .into(),
871 _ => self.convert_vm_error(error),
872 }
873 }
874
875 fn arg_is_borrowed(&self, arg: &Argument) -> bool {
878 self.borrowed.contains_key(arg)
879 }
880
881 fn arg_is_mut_borrowed(&self, arg: &Argument) -> bool {
884 matches!(self.borrowed.get(arg), Some(true))
885 }
886
887 fn borrow_mut(
890 &mut self,
891 arg: Argument,
892 usage: UsageKind,
893 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), CommandArgumentError>
894 {
895 self.borrow_mut_impl(arg, Some(usage))
896 }
897
898 fn borrow_mut_impl(
901 &mut self,
902 arg: Argument,
903 update_last_usage: Option<UsageKind>,
904 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), CommandArgumentError>
905 {
906 let (metadata, result_value) = match arg {
907 Argument::GasCoin => (self.gas.object_metadata.as_ref(), &mut self.gas.inner),
908 Argument::Input(i) => {
909 let Some(input_value) = self.inputs.get_mut(i as usize) else {
910 return Err(CommandArgumentError::IndexOutOfBounds { idx: i });
911 };
912 (input_value.object_metadata.as_ref(), &mut input_value.inner)
913 }
914 Argument::Result(i) => {
915 let Some(command_result) = self.results.get_mut(i as usize) else {
916 return Err(CommandArgumentError::IndexOutOfBounds { idx: i });
917 };
918 if command_result.len() != 1 {
919 return Err(CommandArgumentError::InvalidResultArity { result_idx: i });
920 }
921 (None, &mut command_result[0])
922 }
923 Argument::NestedResult(i, j) => {
924 let Some(command_result) = self.results.get_mut(i as usize) else {
925 return Err(CommandArgumentError::IndexOutOfBounds { idx: i });
926 };
927 let Some(result_value) = command_result.get_mut(j as usize) else {
928 return Err(CommandArgumentError::SecondaryIndexOutOfBounds {
929 result_idx: i,
930 secondary_idx: j,
931 });
932 };
933 (None, result_value)
934 }
935 };
936 if let Some(usage) = update_last_usage {
937 result_value.last_usage_kind = Some(usage);
938 }
939 Ok((metadata, &mut result_value.value))
940 }
941
942 pub(crate) fn execute_function_bypass_visibility(
947 &mut self,
948 module: &ModuleId,
949 function_name: &IdentStr,
950 ty_args: Vec<Type>,
951 args: Vec<impl Borrow<[u8]>>,
952 tracer: &mut Option<MoveTraceBuilder>,
953 ) -> VMResult<SerializedReturnValues> {
954 let gas_status = self.gas_charger.move_gas_status_mut();
955 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
956 self.vm.get_runtime().execute_function_bypass_visibility(
957 module,
958 function_name,
959 ty_args,
960 args,
961 &mut data_store,
962 gas_status,
963 &mut self.native_extensions,
964 tracer.as_mut(),
965 )
966 }
967
968 pub(crate) fn load_function(
973 &mut self,
974 module_id: &ModuleId,
975 function_name: &IdentStr,
976 type_arguments: &[Type],
977 ) -> VMResult<LoadedFunctionInstantiation> {
978 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
979 self.vm.get_runtime().load_function(
980 module_id,
981 function_name,
982 type_arguments,
983 &mut data_store,
984 )
985 }
986
987 pub(crate) fn make_object_value(
992 &mut self,
993 type_: MoveObjectType,
994 used_in_non_entry_move_call: bool,
995 contents: &[u8],
996 ) -> Result<ObjectValue, ExecutionError> {
997 make_object_value(
998 self.vm,
999 &mut self.linkage_view,
1000 &self.new_packages,
1001 type_,
1002 used_in_non_entry_move_call,
1003 contents,
1004 )
1005 }
1006
1007 pub fn publish_module_bundle(
1012 &mut self,
1013 modules: Vec<Vec<u8>>,
1014 sender: AccountAddress,
1015 ) -> VMResult<()> {
1016 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1019 self.vm.get_runtime().publish_module_bundle(
1020 modules,
1021 sender,
1022 &mut data_store,
1023 self.gas_charger.move_gas_status_mut(),
1024 )
1025 }
1026 }
1027
1028 impl TypeTagResolver for ExecutionContext<'_, '_, '_> {
1029 fn get_type_tag(&self, type_: &Type) -> Result<TypeTag, ExecutionError> {
1032 self.vm
1033 .get_runtime()
1034 .get_type_tag(type_)
1035 .map_err(|e| self.convert_vm_error(e))
1036 }
1037 }
1038
1039 fn package_for_linkage(
1043 linkage_view: &LinkageView,
1044 package_id: ObjectID,
1045 ) -> VMResult<PackageObject> {
1046 use move_binary_format::errors::PartialVMError;
1047 use move_core_types::vm_status::StatusCode;
1048
1049 match linkage_view.get_package_object(&package_id) {
1050 Ok(Some(package)) => Ok(package),
1051 Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1052 .with_message(format!("Cannot find link context {package_id} in store"))
1053 .finish(Location::Undefined)),
1054 Err(err) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1055 .with_message(format!(
1056 "Error loading link context {package_id} from store: {err}"
1057 ))
1058 .finish(Location::Undefined)),
1059 }
1060 }
1061
1062 pub fn load_type_from_struct(
1068 vm: &MoveVM,
1069 linkage_view: &mut LinkageView,
1070 new_packages: &[MovePackage],
1071 struct_tag: &StructTag,
1072 ) -> VMResult<Type> {
1073 fn verification_error<T>(code: StatusCode) -> VMResult<T> {
1074 Err(PartialVMError::new(code).finish(Location::Undefined))
1075 }
1076
1077 let StructTag {
1078 address,
1079 module,
1080 name,
1081 type_params,
1082 } = struct_tag;
1083
1084 let defining_id = ObjectID::from_address(*address);
1086 let package = package_for_linkage(linkage_view, defining_id)?;
1087
1088 let original_address = linkage_view
1091 .set_linkage(package.move_package())
1092 .map_err(|e| {
1093 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1094 .with_message(e.to_string())
1095 .finish(Location::Undefined)
1096 })?;
1097
1098 let runtime_id = ModuleId::new(original_address, module.clone());
1099 let data_store = IotaDataStore::new(linkage_view, new_packages);
1100 let res = vm.get_runtime().load_type(&runtime_id, name, &data_store);
1101 linkage_view.reset_linkage();
1102 let (idx, struct_type) = res?;
1103
1104 let type_param_constraints = struct_type.type_param_constraints();
1106 if type_param_constraints.len() != type_params.len() {
1107 return verification_error(StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH);
1108 }
1109
1110 if type_params.is_empty() {
1111 Ok(Type::Datatype(idx))
1112 } else {
1113 let loaded_type_params = type_params
1114 .iter()
1115 .map(|type_param| load_type(vm, linkage_view, new_packages, type_param))
1116 .collect::<VMResult<Vec<_>>>()?;
1117
1118 for (constraint, param) in type_param_constraints.zip(&loaded_type_params) {
1120 let abilities = vm.get_runtime().get_type_abilities(param)?;
1121 if !constraint.is_subset(abilities) {
1122 return verification_error(StatusCode::CONSTRAINT_NOT_SATISFIED);
1123 }
1124 }
1125
1126 Ok(Type::DatatypeInstantiation(Box::new((
1127 idx,
1128 loaded_type_params,
1129 ))))
1130 }
1131 }
1132
1133 pub fn load_type(
1137 vm: &MoveVM,
1138 linkage_view: &mut LinkageView,
1139 new_packages: &[MovePackage],
1140 type_tag: &TypeTag,
1141 ) -> VMResult<Type> {
1142 Ok(match type_tag {
1143 TypeTag::Bool => Type::Bool,
1144 TypeTag::U8 => Type::U8,
1145 TypeTag::U16 => Type::U16,
1146 TypeTag::U32 => Type::U32,
1147 TypeTag::U64 => Type::U64,
1148 TypeTag::U128 => Type::U128,
1149 TypeTag::U256 => Type::U256,
1150 TypeTag::Address => Type::Address,
1151 TypeTag::Signer => Type::Signer,
1152
1153 TypeTag::Vector(inner) => {
1154 Type::Vector(Box::new(load_type(vm, linkage_view, new_packages, inner)?))
1155 }
1156 TypeTag::Struct(struct_tag) => {
1157 return load_type_from_struct(vm, linkage_view, new_packages, struct_tag);
1158 }
1159 })
1160 }
1161
1162 pub(crate) fn make_object_value(
1169 vm: &MoveVM,
1170 linkage_view: &mut LinkageView,
1171 new_packages: &[MovePackage],
1172 type_: MoveObjectType,
1173 used_in_non_entry_move_call: bool,
1174 contents: &[u8],
1175 ) -> Result<ObjectValue, ExecutionError> {
1176 let contents = if type_.is_coin() {
1177 let Ok(coin) = Coin::from_bcs_bytes(contents) else {
1178 invariant_violation!("Could not deserialize a coin")
1179 };
1180 ObjectContents::Coin(coin)
1181 } else {
1182 ObjectContents::Raw(contents.to_vec())
1183 };
1184
1185 let tag: StructTag = type_.into();
1186 let type_ = load_type_from_struct(vm, linkage_view, new_packages, &tag)
1187 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1188 let abilities = vm
1189 .get_runtime()
1190 .get_type_abilities(&type_)
1191 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1192 let has_public_transfer = abilities.has_store();
1193 Ok(ObjectValue {
1194 type_,
1195 has_public_transfer,
1196 used_in_non_entry_move_call,
1197 contents,
1198 })
1199 }
1200
1201 pub(crate) fn value_from_object(
1206 vm: &MoveVM,
1207 linkage_view: &mut LinkageView,
1208 new_packages: &[MovePackage],
1209 object: &Object,
1210 ) -> Result<ObjectValue, ExecutionError> {
1211 let ObjectInner {
1212 data: Data::Move(object),
1213 ..
1214 } = object.as_inner()
1215 else {
1216 invariant_violation!("Expected a Move object");
1217 };
1218
1219 let used_in_non_entry_move_call = false;
1220 make_object_value(
1221 vm,
1222 linkage_view,
1223 new_packages,
1224 object.type_().clone(),
1225 used_in_non_entry_move_call,
1226 object.contents(),
1227 )
1228 }
1229
1230 fn load_object(
1232 vm: &MoveVM,
1233 state_view: &dyn ExecutionState,
1234 linkage_view: &mut LinkageView,
1235 new_packages: &[MovePackage],
1236 input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1237 override_as_immutable: bool,
1238 id: ObjectID,
1239 ) -> Result<InputValue, ExecutionError> {
1240 let Some(obj) = state_view.read_object(&id) else {
1241 invariant_violation!("Object {} does not exist yet", id);
1243 };
1244 assert_invariant!(
1246 !override_as_immutable || matches!(obj.owner, Owner::Shared { .. }),
1247 "override_as_immutable should only be set for shared objects"
1248 );
1249 let is_mutable_input = match obj.owner {
1250 Owner::AddressOwner(_) => true,
1251 Owner::Shared { .. } => !override_as_immutable,
1252 Owner::Immutable => false,
1253 Owner::ObjectOwner(_) => {
1254 invariant_violation!("ObjectOwner objects cannot be input")
1256 }
1257 };
1258 let owner = obj.owner;
1259 let version = obj.version();
1260 let object_metadata = InputObjectMetadata::InputObject {
1261 id,
1262 is_mutable_input,
1263 owner,
1264 version,
1265 };
1266 let obj_value = value_from_object(vm, linkage_view, new_packages, obj)?;
1267 let contained_uids = {
1268 let fully_annotated_layout = vm
1269 .get_runtime()
1270 .type_to_fully_annotated_layout(&obj_value.type_)
1271 .map_err(|e| convert_vm_error(e, vm, linkage_view))?;
1272 let mut bytes = vec![];
1273 obj_value.write_bcs_bytes(&mut bytes, None)?;
1274 match get_all_uids(&fully_annotated_layout, &bytes) {
1275 Err(e) => {
1276 invariant_violation!("Unable to retrieve UIDs for object. Got error: {e}")
1277 }
1278 Ok(uids) => uids,
1279 }
1280 };
1281 let runtime_input = object_runtime::InputObject {
1282 contained_uids,
1283 owner,
1284 version,
1285 };
1286 let prev = input_object_map.insert(id, runtime_input);
1287 assert_invariant!(prev.is_none(), "Duplicate input object {}", id);
1289 Ok(InputValue::new_object(object_metadata, obj_value))
1290 }
1291
1292 fn load_call_arg(
1294 vm: &MoveVM,
1295 state_view: &dyn ExecutionState,
1296 linkage_view: &mut LinkageView,
1297 new_packages: &[MovePackage],
1298 input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1299 call_arg: CallArg,
1300 ) -> Result<InputValue, ExecutionError> {
1301 Ok(match call_arg {
1302 CallArg::Pure(bytes) => InputValue::new_raw(RawValueType::Any, bytes),
1303 CallArg::Object(obj_arg) => load_object_arg(
1304 vm,
1305 state_view,
1306 linkage_view,
1307 new_packages,
1308 input_object_map,
1309 obj_arg,
1310 )?,
1311 })
1312 }
1313
1314 fn load_object_arg(
1317 vm: &MoveVM,
1318 state_view: &dyn ExecutionState,
1319 linkage_view: &mut LinkageView,
1320 new_packages: &[MovePackage],
1321 input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1322 obj_arg: ObjectArg,
1323 ) -> Result<InputValue, ExecutionError> {
1324 match obj_arg {
1325 ObjectArg::ImmOrOwnedObject((id, _, _)) => load_object(
1326 vm,
1327 state_view,
1328 linkage_view,
1329 new_packages,
1330 input_object_map,
1331 false,
1333 id,
1334 ),
1335 ObjectArg::SharedObject { id, mutable, .. } => load_object(
1336 vm,
1337 state_view,
1338 linkage_view,
1339 new_packages,
1340 input_object_map,
1341 !mutable,
1343 id,
1344 ),
1345 ObjectArg::Receiving((id, version, _)) => {
1346 Ok(InputValue::new_receiving_object(id, version))
1347 }
1348 }
1349 }
1350
1351 fn add_additional_write(
1353 additional_writes: &mut BTreeMap<ObjectID, AdditionalWrite>,
1354 owner: Owner,
1355 object_value: ObjectValue,
1356 ) -> Result<(), ExecutionError> {
1357 let ObjectValue {
1358 type_, contents, ..
1359 } = object_value;
1360 let bytes = match contents {
1361 ObjectContents::Coin(coin) => coin.to_bcs_bytes(),
1362 ObjectContents::Raw(bytes) => bytes,
1363 };
1364 let object_id = MoveObject::id_opt(&bytes).map_err(|e| {
1365 ExecutionError::invariant_violation(format!("No id for Raw object bytes. {e}"))
1366 })?;
1367 let additional_write = AdditionalWrite {
1368 recipient: owner,
1369 type_,
1370 bytes,
1371 };
1372 additional_writes.insert(object_id, additional_write);
1373 Ok(())
1374 }
1375
1376 fn refund_max_gas_budget(
1380 additional_writes: &mut BTreeMap<ObjectID, AdditionalWrite>,
1381 gas_charger: &mut GasCharger,
1382 gas_id: ObjectID,
1383 ) -> Result<(), ExecutionError> {
1384 let Some(AdditionalWrite { bytes, .. }) = additional_writes.get_mut(&gas_id) else {
1385 invariant_violation!("Gas object cannot be wrapped or destroyed")
1386 };
1387 let Ok(mut coin) = Coin::from_bcs_bytes(bytes) else {
1388 invariant_violation!("Gas object must be a coin")
1389 };
1390 let Some(new_balance) = coin.balance.value().checked_add(gas_charger.gas_budget()) else {
1391 return Err(ExecutionError::new_with_source(
1392 ExecutionErrorKind::CoinBalanceOverflow,
1393 "Gas coin too large after returning the max gas budget",
1394 ));
1395 };
1396 coin.balance = Balance::new(new_balance);
1397 *bytes = coin.to_bcs_bytes();
1398 Ok(())
1399 }
1400
1401 fn create_written_object(
1403 vm: &MoveVM,
1404 linkage_view: &LinkageView,
1405 protocol_config: &ProtocolConfig,
1406 objects_modified_at: &BTreeMap<ObjectID, LoadedRuntimeObject>,
1407 id: ObjectID,
1408 type_: Type,
1409 contents: Vec<u8>,
1410 ) -> Result<MoveObject, ExecutionError> {
1411 debug_assert_eq!(
1412 id,
1413 MoveObject::id_opt(&contents).expect("object contents should start with an id")
1414 );
1415 let old_obj_ver = objects_modified_at
1416 .get(&id)
1417 .map(|obj: &LoadedRuntimeObject| obj.version);
1418
1419 let type_tag = vm
1420 .get_runtime()
1421 .get_type_tag(&type_)
1422 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1423
1424 let struct_tag = match type_tag {
1425 TypeTag::Struct(inner) => *inner,
1426 _ => invariant_violation!("Non struct type for object"),
1427 };
1428 MoveObject::new_from_execution(
1429 struct_tag.into(),
1430 old_obj_ver.unwrap_or_default(),
1431 contents,
1432 protocol_config,
1433 )
1434 }
1435
1436 pub(crate) struct IotaDataStore<'state, 'a> {
1444 linkage_view: &'a LinkageView<'state>,
1445 new_packages: &'a [MovePackage],
1446 }
1447
1448 impl<'state, 'a> IotaDataStore<'state, 'a> {
1449 pub(crate) fn new(
1450 linkage_view: &'a LinkageView<'state>,
1451 new_packages: &'a [MovePackage],
1452 ) -> Self {
1453 Self {
1454 linkage_view,
1455 new_packages,
1456 }
1457 }
1458
1459 fn get_module(&self, module_id: &ModuleId) -> Option<&Vec<u8>> {
1460 for package in self.new_packages {
1461 let module = package.get_module(module_id);
1462 if module.is_some() {
1463 return module;
1464 }
1465 }
1466 None
1467 }
1468 }
1469
1470 impl DataStore for IotaDataStore<'_, '_> {
1474 fn link_context(&self) -> AccountAddress {
1475 self.linkage_view.link_context()
1476 }
1477
1478 fn relocate(&self, module_id: &ModuleId) -> PartialVMResult<ModuleId> {
1479 self.linkage_view.relocate(module_id).map_err(|err| {
1480 PartialVMError::new(StatusCode::LINKER_ERROR)
1481 .with_message(format!("Error relocating {module_id}: {err:?}"))
1482 })
1483 }
1484
1485 fn defining_module(
1486 &self,
1487 runtime_id: &ModuleId,
1488 struct_: &IdentStr,
1489 ) -> PartialVMResult<ModuleId> {
1490 self.linkage_view
1491 .defining_module(runtime_id, struct_)
1492 .map_err(|err| {
1493 PartialVMError::new(StatusCode::LINKER_ERROR).with_message(format!(
1494 "Error finding defining module for {runtime_id}::{struct_}: {err:?}"
1495 ))
1496 })
1497 }
1498
1499 fn load_module(&self, module_id: &ModuleId) -> VMResult<Vec<u8>> {
1500 if let Some(bytes) = self.get_module(module_id) {
1501 return Ok(bytes.clone());
1502 }
1503 match self.linkage_view.get_module(module_id) {
1504 Ok(Some(bytes)) => Ok(bytes),
1505 Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1506 .with_message(format!("Cannot find {:?} in data cache", module_id))
1507 .finish(Location::Undefined)),
1508 Err(err) => {
1509 let msg = format!("Unexpected storage error: {:?}", err);
1510 Err(
1511 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1512 .with_message(msg)
1513 .finish(Location::Undefined),
1514 )
1515 }
1516 }
1517 }
1518
1519 fn publish_module(&mut self, _module_id: &ModuleId, _blob: Vec<u8>) -> VMResult<()> {
1520 Ok(())
1523 }
1524 }
1525}