1pub use checked::*;
6
7#[iota_macros::with_checked_arithmetic]
8mod checked {
9 use std::{
10 borrow::Borrow,
11 cell::RefCell,
12 collections::{BTreeMap, BTreeSet, HashMap},
13 rc::Rc,
14 sync::Arc,
15 };
16
17 use iota_move_natives::object_runtime::{
18 self, LoadedRuntimeObject, ObjectRuntime, RuntimeResults, get_all_uids, max_event_error,
19 };
20 use iota_protocol_config::ProtocolConfig;
21 use iota_sdk_types::{
22 Address, Argument, CommandArgumentError, Event, ObjectData, ObjectId, Owner,
23 SharedObjectReference, StructTag, TypeTag, move_package::MovePackage,
24 };
25 use iota_types::{
26 balance::Balance,
27 base_types::TxContext,
28 coin::Coin,
29 error::{ExecutionError, ExecutionErrorKind, command_argument_error},
30 execution::{ExecutionResults, ExecutionResultsV1},
31 iota_sdk_types_conversions::{
32 identifier_core_to_sdk, identifier_sdk_to_core, struct_tag_core_to_sdk,
33 type_tag_core_to_sdk,
34 },
35 metrics::LimitsMetrics,
36 move_package::{MovePackageExt, derive_package_metadata_id},
37 object::{MoveObject, MoveObjectExt, Object, ObjectInner},
38 storage::{BackingPackageStore, DenyListResult, PackageObject},
39 transaction::CallArg,
40 };
41 use move_binary_format::{
42 CompiledModule,
43 errors::{Location, PartialVMError, PartialVMResult, VMError, VMResult},
44 file_format::{CodeOffset, FunctionDefinitionIndex, TypeParameterIndex},
45 };
46 use move_core_types::{
47 account_address::AccountAddress, identifier::IdentStr, language_storage::ModuleId,
48 resolver::ModuleResolver, vm_status::StatusCode,
49 };
50 use move_trace_format::format::MoveTraceBuilder;
51 use move_vm_runtime::{
52 move_vm::MoveVM,
53 native_extensions::NativeContextExtensions,
54 session::{LoadedFunctionInstantiation, SerializedReturnValues},
55 };
56 use move_vm_types::{data_store::DataStore, loaded_data::runtime_types::Type};
57 use tracing::instrument;
58
59 use crate::{
60 adapter::new_native_extensions,
61 error::convert_vm_error,
62 execution_mode::ExecutionMode,
63 execution_value::{
64 CommandKind, ExecutionState, InputObjectMetadata, InputValue, ObjectContents,
65 ObjectValue, RawValueType, ResultValue, TryFromValue, UsageKind, Value,
66 },
67 gas_charger::GasCharger,
68 gas_meter::IotaGasMeter,
69 programmable_transactions::linkage_view::LinkageView,
70 type_resolver::TypeTagResolver,
71 };
72
73 pub struct ExecutionContext<'vm, 'state, 'a> {
75 pub protocol_config: &'a ProtocolConfig,
77 pub metrics: Arc<LimitsMetrics>,
79 pub vm: &'vm MoveVM,
81 pub linkage_view: LinkageView<'state>,
83 pub native_extensions: NativeContextExtensions<'state>,
84 pub state_view: &'state dyn ExecutionState,
86 pub tx_context: Rc<RefCell<TxContext>>,
89 pub gas_charger: &'a mut GasCharger,
91 additional_transfers: Vec<(Owner, ObjectValue)>,
93 new_packages: Vec<MovePackage>,
95 user_events: Vec<(ModuleId, StructTag, Vec<u8>)>,
97 gas: InputValue,
100 inputs: Vec<InputValue>,
103 results: Vec<Vec<ResultValue>>,
108 borrowed: HashMap<Arg, bool>,
112 }
113
114 struct AdditionalWrite {
117 recipient: Owner,
119 type_: Type,
121 bytes: Vec<u8>,
123 }
124
125 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
126 pub struct Arg(Arg_);
127
128 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
129 enum Arg_ {
130 V1(Argument),
131 V2(NormalizedArg),
132 }
133
134 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
135 enum NormalizedArg {
136 GasCoin,
137 Input(u16),
138 Result(u16, u16),
139 }
140
141 impl<'vm, 'state, 'a> ExecutionContext<'vm, 'state, 'a> {
142 #[instrument(name = "ExecutionContext::new", level = "trace", skip_all)]
149 pub fn new(
150 protocol_config: &'a ProtocolConfig,
151 metrics: Arc<LimitsMetrics>,
152 vm: &'vm MoveVM,
153 state_view: &'state dyn ExecutionState,
154 tx_context: Rc<RefCell<TxContext>>,
155 gas_charger: &'a mut GasCharger,
156 inputs: Vec<CallArg>,
157 ) -> Result<Self, ExecutionError>
158 where
159 'a: 'state,
160 {
161 let mut linkage_view = LinkageView::new(Box::new(state_view.as_iota_resolver()));
162 let mut input_object_map = BTreeMap::new();
163 let inputs = inputs
164 .into_iter()
165 .map(|call_arg| {
166 load_call_arg(
167 vm,
168 state_view,
169 &mut linkage_view,
170 &[],
171 &mut input_object_map,
172 call_arg,
173 )
174 })
175 .collect::<Result<_, ExecutionError>>()?;
176 let gas = if let Some(gas_coin) = gas_charger.gas_coin() {
177 let mut gas = load_object(
178 vm,
179 state_view,
180 &mut linkage_view,
181 &[],
182 &mut input_object_map,
183 false,
185 gas_coin,
186 )?;
187 let Some(Value::Object(ObjectValue {
191 contents: ObjectContents::Coin(coin),
192 ..
193 })) = &mut gas.inner.value
194 else {
195 invariant_violation!("Gas object should be a populated coin")
196 };
197
198 let max_gas_in_balance = gas_charger.gas_budget();
199 let Some(new_balance) = coin.balance.value().checked_sub(max_gas_in_balance) else {
200 invariant_violation!(
201 "Transaction input checker should check that there is enough gas"
202 );
203 };
204 coin.balance = Balance::new(new_balance);
205 gas
206 } else {
207 InputValue {
208 object_metadata: None,
209 inner: ResultValue {
210 last_usage_kind: None,
211 value: None,
212 },
213 }
214 };
215 let native_extensions = new_native_extensions(
216 state_view.as_child_resolver(),
217 input_object_map,
218 !gas_charger.is_unmetered(),
219 protocol_config,
220 metrics.clone(),
221 tx_context.clone(),
222 state_view.read_auth_context(),
223 );
224
225 #[skip_checked_arithmetic]
227 move_vm_profiler::tracing_feature_enabled! {
228 use move_vm_profiler::GasProfiler;
229 use move_vm_types::gas::GasMeter;
230
231 let ref_context: &RefCell<TxContext> = tx_context.borrow();
232 let tx_digest = ref_context.borrow().digest();
233 let remaining_gas: u64 =
234 move_vm_types::gas::GasMeter::remaining_gas(&IotaGasMeter(gas_charger.move_gas_status_mut()))
235 .into();
236 IotaGasMeter(gas_charger.move_gas_status_mut())
237 .set_profiler(GasProfiler::init(
238 &vm.config().profiler_config,
239 format!("{tx_digest}"),
240 remaining_gas,
241 ));
242 }
243
244 Ok(Self {
245 protocol_config,
246 metrics,
247 vm,
248 linkage_view,
249 native_extensions,
250 state_view,
251 tx_context,
252 gas_charger,
253 gas,
254 inputs,
255 results: vec![],
256 additional_transfers: vec![],
257 new_packages: vec![],
258 user_events: vec![],
259 borrowed: HashMap::new(),
260 })
261 }
262
263 pub fn object_runtime(&self) -> Result<&ObjectRuntime<'_>, ExecutionError> {
264 self.native_extensions
265 .get::<ObjectRuntime>()
266 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))
267 }
268
269 pub fn fresh_id(&mut self) -> Result<ObjectId, ExecutionError> {
271 let object_id = self.tx_context.borrow_mut().fresh_id();
272 self.record_new_uid(object_id)?;
273 Ok(object_id)
274 }
275
276 pub(crate) fn record_new_uid(&mut self, object_id: ObjectId) -> Result<(), ExecutionError> {
278 self.native_extensions
279 .get_mut()
280 .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.new_id(object_id))
281 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
282 Ok(())
283 }
284
285 pub(crate) fn package_derived_metadata_id(
287 &mut self,
288 package_storage_id: ObjectId,
289 ) -> Result<ObjectId, ExecutionError> {
290 let object_id = derive_package_metadata_id(package_storage_id);
291 self.record_new_uid(object_id)?;
292 Ok(object_id)
293 }
294
295 pub fn delete_id(&mut self, object_id: ObjectId) -> Result<(), ExecutionError> {
297 self.native_extensions
298 .get_mut()
299 .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.delete_id(object_id))
300 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))
301 }
302
303 pub fn set_link_context(
307 &mut self,
308 package_id: ObjectId,
309 ) -> Result<AccountAddress, ExecutionError> {
310 if self.linkage_view.has_linkage(package_id) {
311 return Ok(self
313 .linkage_view
314 .original_package_id()
315 .unwrap_or(AccountAddress::new(package_id.into_bytes())));
316 }
317
318 let package = package_for_linkage(&self.linkage_view, package_id)
319 .map_err(|e| self.convert_vm_error(e))?;
320
321 self.linkage_view.set_linkage(package.move_package())
322 }
323
324 pub fn load_type(&mut self, type_tag: &TypeTag) -> VMResult<Type> {
326 load_type(
327 self.vm,
328 &mut self.linkage_view,
329 &self.new_packages,
330 type_tag,
331 )
332 }
333
334 pub fn load_type_from_struct(&mut self, struct_tag: &StructTag) -> VMResult<Type> {
336 load_type_from_struct(
337 self.vm,
338 &mut self.linkage_view,
339 &self.new_packages,
340 struct_tag,
341 )
342 }
343
344 pub fn take_user_events(
347 &mut self,
348 module_id: &ModuleId,
349 function: FunctionDefinitionIndex,
350 last_offset: CodeOffset,
351 ) -> Result<(), ExecutionError> {
352 let events = self
353 .native_extensions
354 .get_mut()
355 .map(|object_runtime: &mut ObjectRuntime| object_runtime.take_user_events())
356 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
357 let num_events = self.user_events.len() + events.len();
358 let max_events = self.protocol_config.max_num_event_emit();
359 if num_events as u64 > max_events {
360 let err = max_event_error(max_events)
361 .at_code_offset(function, last_offset)
362 .finish(Location::Module(module_id.clone()));
363 return Err(self.convert_vm_error(err));
364 }
365 let new_events = events
366 .into_iter()
367 .map(|(ty, tag, value)| {
368 let layout = self
369 .vm
370 .get_runtime()
371 .type_to_type_layout(&ty)
372 .map_err(|e| self.convert_vm_error(e))?;
373 let Some(bytes) = value.simple_serialize(&layout) else {
374 invariant_violation!("Failed to deserialize already serialized Move value");
375 };
376 Ok((module_id.clone(), struct_tag_core_to_sdk(&tag), bytes))
377 })
378 .collect::<Result<Vec<_>, ExecutionError>>()?;
379 self.user_events.extend(new_events);
380 Ok(())
381 }
382
383 pub fn splat_args<Items: IntoIterator<Item = Argument>>(
389 &self,
390 start_idx: usize,
391 args: Items,
392 ) -> Result<Vec<Arg>, ExecutionError>
393 where
394 Items::IntoIter: ExactSizeIterator,
395 {
396 if !self.protocol_config.normalize_ptb_arguments() {
397 Ok(args.into_iter().map(|arg| Arg(Arg_::V1(arg))).collect())
398 } else {
399 let args = args.into_iter();
400 let _args_len = args.len();
401 let mut res = vec![];
402 for (arg_idx, arg) in args.enumerate() {
403 self.splat_arg(&mut res, arg)
404 .map_err(|e| e.into_execution_error(start_idx + arg_idx))?;
405 }
406 debug_assert_eq!(res.len(), _args_len);
407 Ok(res)
408 }
409 }
410
411 fn splat_arg(&self, res: &mut Vec<Arg>, arg: Argument) -> Result<(), EitherError> {
412 match arg {
413 Argument::Gas => res.push(Arg(Arg_::V2(NormalizedArg::GasCoin))),
414 Argument::Input(i) => {
415 if i as usize >= self.inputs.len() {
416 return Err(CommandArgumentError::IndexOutOfBounds { index: i }.into());
417 }
418 res.push(Arg(Arg_::V2(NormalizedArg::Input(i))))
419 }
420 Argument::NestedResult(i, j) => {
421 let Some(command_result) = self.results.get(i as usize) else {
422 return Err(CommandArgumentError::IndexOutOfBounds { index: i }.into());
423 };
424 if j as usize >= command_result.len() {
425 return Err(CommandArgumentError::SecondaryIndexOutOfBounds {
426 result: i,
427 subresult: j,
428 }
429 .into());
430 };
431 res.push(Arg(Arg_::V2(NormalizedArg::Result(i, j))))
432 }
433 Argument::Result(i) => {
434 let Some(result) = self.results.get(i as usize) else {
435 return Err(CommandArgumentError::IndexOutOfBounds { index: i }.into());
436 };
437 let Ok(len): Result<u16, _> = result.len().try_into() else {
438 invariant_violation!("Result of length greater than u16::MAX");
439 };
440 if len != 1 {
441 return Err(CommandArgumentError::InvalidResultArity { result: i }.into());
443 }
444 res.extend((0..len).map(|j| Arg(Arg_::V2(NormalizedArg::Result(i, j)))))
445 }
446 _ => {
447 unimplemented!("a new Argument enum variant was added and needs to be handled")
448 }
449 }
450 Ok(())
451 }
452
453 pub fn one_arg(
454 &self,
455 command_arg_idx: usize,
456 arg: Argument,
457 ) -> Result<Arg, ExecutionError> {
458 let args = self.splat_args(command_arg_idx, vec![arg])?;
459 let Ok([arg]): Result<[Arg; 1], _> = args.try_into() else {
460 return Err(command_argument_error(
461 CommandArgumentError::InvalidArgumentArity,
462 command_arg_idx,
463 ));
464 };
465 Ok(arg)
466 }
467
468 pub(crate) fn add_pure_input(
475 &mut self,
476 bytes: Vec<u8>,
477 ) -> Result<Argument, ExecutionError> {
478 let Ok(index) = u16::try_from(self.inputs.len()) else {
479 invariant_violation!("too many inputs to register an additional pure input");
480 };
481 self.inputs
482 .push(InputValue::new_raw(RawValueType::Any, bytes));
483 Ok(Argument::Input(index))
484 }
485
486 pub(crate) fn num_inputs(&self) -> usize {
490 self.inputs.len()
491 }
492
493 pub(crate) fn truncate_inputs(&mut self, len: usize) {
497 self.inputs.truncate(len);
498 }
499
500 pub fn by_value_arg<V: TryFromValue>(
506 &mut self,
507 command_kind: CommandKind,
508 arg_idx: usize,
509 arg: Arg,
510 ) -> Result<V, ExecutionError> {
511 self.by_value_arg_(command_kind, arg)
512 .map_err(|e| e.into_execution_error(arg_idx))
513 }
514 fn by_value_arg_<V: TryFromValue>(
515 &mut self,
516 command_kind: CommandKind,
517 arg: Arg,
518 ) -> Result<V, EitherError> {
519 let is_borrowed = self.arg_is_borrowed(&arg);
520 let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::ByValue)?;
521 let is_copyable = if let Some(val) = val_opt {
522 val.is_copyable()
523 } else {
524 return Err(CommandArgumentError::InvalidValueUsage.into());
525 };
526 if !is_copyable && is_borrowed {
532 return Err(CommandArgumentError::InvalidValueUsage.into());
533 }
534 if arg.is_gas_coin() && !matches!(command_kind, CommandKind::TransferObjects) {
536 return Err(CommandArgumentError::InvalidGasCoinUsage.into());
537 }
538 if matches!(
540 input_metadata_opt,
541 Some(InputObjectMetadata::InputObject {
542 owner: Owner::Immutable,
543 ..
544 })
545 ) {
546 return Err(CommandArgumentError::InvalidObjectByValue.into());
547 }
548
549 if matches!(
551 input_metadata_opt,
552 Some(InputObjectMetadata::InputObject {
553 is_mutable_input: false,
554 ..
555 })
556 ) {
557 return Err(CommandArgumentError::InvalidObjectByValue.into());
558 }
559
560 let val = if is_copyable {
561 val_opt.as_ref().unwrap().clone()
562 } else {
563 val_opt.take().unwrap()
564 };
565 Ok(V::try_from_value(val)?)
566 }
567
568 pub fn borrow_arg_mut<V: TryFromValue>(
575 &mut self,
576 arg_idx: usize,
577 arg: Arg,
578 ) -> Result<V, ExecutionError> {
579 self.borrow_arg_mut_(arg)
580 .map_err(|e| e.into_execution_error(arg_idx))
581 }
582 fn borrow_arg_mut_<V: TryFromValue>(&mut self, arg: Arg) -> Result<V, EitherError> {
583 if self.arg_is_borrowed(&arg) {
585 return Err(CommandArgumentError::InvalidValueUsage.into());
586 }
587 self.borrowed.insert(arg, true);
588 let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowMut)?;
589 let is_copyable = if let Some(val) = val_opt {
590 val.is_copyable()
591 } else {
592 return Err(CommandArgumentError::InvalidValueUsage.into());
594 };
595 if let Some(InputObjectMetadata::InputObject {
596 is_mutable_input: false,
597 ..
598 }) = input_metadata_opt
599 {
600 return Err(CommandArgumentError::InvalidObjectByMutRef.into());
601 }
602 let val = if is_copyable {
605 val_opt.as_ref().unwrap().clone()
606 } else {
607 val_opt.take().unwrap()
608 };
609 Ok(V::try_from_value(val)?)
610 }
611
612 pub fn borrow_arg<V: TryFromValue>(
617 &mut self,
618 arg_idx: usize,
619 arg: Arg,
620 type_: &Type,
621 ) -> Result<V, ExecutionError> {
622 self.borrow_arg_(arg, type_)
623 .map_err(|e| e.into_execution_error(arg_idx))
624 }
625 fn borrow_arg_<V: TryFromValue>(
626 &mut self,
627 arg: Arg,
628 arg_type: &Type,
629 ) -> Result<V, EitherError> {
630 if self.arg_is_mut_borrowed(&arg) {
634 return Err(CommandArgumentError::InvalidValueUsage.into());
635 }
636 self.borrowed.insert(arg, false);
637 let (_input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowImm)?;
638 if val_opt.is_none() {
639 return Err(CommandArgumentError::InvalidValueUsage.into());
640 }
641
642 if let &mut Some(Value::Receiving(_, _, ref mut recv_arg_type @ None)) = val_opt {
644 let Type::Reference(inner) = arg_type else {
645 return Err(CommandArgumentError::InvalidValueUsage.into());
646 };
647 *recv_arg_type = Some(*(*inner).clone());
648 }
649
650 Ok(V::try_from_value(val_opt.as_ref().unwrap().clone())?)
651 }
652
653 pub fn restore_arg<Mode: ExecutionMode>(
655 &mut self,
656 updates: &mut Mode::ArgumentUpdates,
657 arg: Arg,
658 value: Value,
659 ) -> Result<(), ExecutionError> {
660 Mode::add_argument_update(self, updates, arg.into(), &value)?;
661 let was_mut_opt = self.borrowed.remove(&arg);
662 assert_invariant!(
663 was_mut_opt.is_some() && was_mut_opt.unwrap(),
664 "Should never restore a non-mut borrowed value. \
665 The take+restore is an implementation detail of mutable references"
666 );
667 let Ok((_, value_opt)) = self.borrow_mut_impl(arg, None) else {
669 invariant_violation!("Should be able to borrow argument to restore it")
670 };
671
672 let old_value = value_opt.replace(value);
673 assert_invariant!(
674 old_value.is_none() || old_value.unwrap().is_copyable(),
675 "Should never restore a non-taken value, unless it is copyable. \
676 The take+restore is an implementation detail of mutable references"
677 );
678
679 Ok(())
680 }
681
682 pub fn transfer_object(
684 &mut self,
685 obj: ObjectValue,
686 addr: Address,
687 ) -> Result<(), ExecutionError> {
688 self.additional_transfers.push((Owner::Address(addr), obj));
689 Ok(())
690 }
691
692 pub fn freeze_object(&mut self, obj: ObjectValue) -> Result<(), ExecutionError> {
694 self.additional_transfers.push((Owner::Immutable, obj));
695 Ok(())
696 }
697
698 pub fn new_package<'p>(
700 &self,
701 modules: &[CompiledModule],
702 dependencies: impl IntoIterator<Item = &'p MovePackage>,
703 ) -> Result<MovePackage, ExecutionError> {
704 MovePackage::new_initial(modules, self.protocol_config, dependencies)
705 }
706
707 pub fn upgrade_package<'p>(
710 &self,
711 storage_id: ObjectId,
712 previous_package: &MovePackage,
713 new_modules: &[CompiledModule],
714 dependencies: impl IntoIterator<Item = &'p MovePackage>,
715 ) -> Result<MovePackage, ExecutionError> {
716 previous_package.new_upgraded(
717 storage_id,
718 new_modules,
719 self.protocol_config,
720 dependencies,
721 )
722 }
723
724 pub fn write_package(&mut self, package: MovePackage) {
726 self.new_packages.push(package);
727 }
728
729 pub fn pop_package(&mut self) -> Option<MovePackage> {
735 self.new_packages.pop()
736 }
737
738 pub fn push_command_results(&mut self, results: Vec<Value>) -> Result<(), ExecutionError> {
741 assert_invariant!(
742 self.borrowed.values().all(|is_mut| !is_mut),
743 "all mut borrows should be restored"
744 );
745 self.borrowed = HashMap::new();
747 self.results
748 .push(results.into_iter().map(ResultValue::new).collect());
749 Ok(())
750 }
751
752 pub fn finish<Mode: ExecutionMode>(self) -> Result<ExecutionResults, ExecutionError> {
754 let Self {
755 protocol_config,
756 vm,
757 linkage_view,
758 mut native_extensions,
759 tx_context,
760 gas_charger,
761 additional_transfers,
762 new_packages,
763 gas,
764 inputs,
765 results,
766 user_events,
767 state_view,
768 ..
769 } = self;
770 let ref_context: &RefCell<TxContext> = tx_context.borrow();
771 let tx_digest = ref_context.borrow().digest();
772
773 let gas_id_opt = gas.object_metadata.as_ref().map(|info| info.id());
774 let mut loaded_runtime_objects = BTreeMap::new();
775 let mut additional_writes = BTreeMap::new();
776 let mut by_value_shared_objects = BTreeSet::new();
777 for input in inputs.into_iter().chain(std::iter::once(gas)) {
778 let InputValue {
779 object_metadata:
780 Some(InputObjectMetadata::InputObject {
781 is_mutable_input: true,
783 id,
784 version,
785 owner,
786 }),
787 inner: ResultValue { value, .. },
788 } = input
789 else {
790 continue;
791 };
792 loaded_runtime_objects.insert(
793 id,
794 LoadedRuntimeObject {
795 version,
796 is_modified: true,
797 },
798 );
799 if let Some(Value::Object(object_value)) = value {
800 add_additional_write(&mut additional_writes, owner, object_value)?;
801 } else if owner.is_shared() {
802 by_value_shared_objects.insert(id);
803 }
804 }
805 if !Mode::allow_arbitrary_values() {
808 for (i, command_result) in results.iter().enumerate() {
809 for (j, result_value) in command_result.iter().enumerate() {
810 let ResultValue {
811 last_usage_kind,
812 value,
813 } = result_value;
814 match value {
815 None => (),
816 Some(Value::Object(_)) => {
817 return Err(ExecutionErrorKind::UnusedValueWithoutDrop {
818 result: i as u16,
819 subresult: j as u16,
820 }
821 .into());
822 }
823 Some(Value::Raw(RawValueType::Any, _)) => (),
824 Some(Value::Raw(RawValueType::Loaded { abilities, .. }, _)) => {
825 if abilities.has_drop()
831 || (abilities.has_copy()
832 && matches!(last_usage_kind, Some(UsageKind::ByValue)))
833 {
834 } else {
835 let msg = if abilities.has_copy() {
836 "The value has copy, but not drop. \
837 Its last usage must be by-value so it can be taken."
838 } else {
839 "Unused value without drop"
840 };
841 return Err(ExecutionError::new_with_source(
842 ExecutionErrorKind::UnusedValueWithoutDrop {
843 result: i as u16,
844 subresult: j as u16,
845 },
846 msg,
847 ));
848 }
849 }
850 Some(Value::Receiving(_, _, _)) => (),
852 }
853 }
854 }
855 }
856 for (owner, object_value) in additional_transfers {
858 add_additional_write(&mut additional_writes, owner, object_value)?;
859 }
860 if let Some(gas_id) = gas_id_opt {
862 refund_max_gas_budget(&mut additional_writes, gas_charger, gas_id)?;
863 }
864
865 let object_runtime: ObjectRuntime = native_extensions
866 .remove()
867 .map_err(|e| convert_vm_error(e.finish(Location::Undefined), vm, &linkage_view))?;
868
869 let RuntimeResults {
870 writes,
871 user_events: remaining_events,
872 loaded_child_objects,
873 mut created_object_ids,
874 deleted_object_ids,
875 } = object_runtime.finish()?;
876 assert_invariant!(
877 remaining_events.is_empty(),
878 "Events should be taken after every Move call"
879 );
880
881 loaded_runtime_objects.extend(loaded_child_objects);
882
883 let mut written_objects = BTreeMap::new();
884 for package in new_packages {
885 let package_obj = Object::new_from_package(package, tx_digest);
886 let id = package_obj.id();
887 created_object_ids.insert(id);
888 written_objects.insert(id, package_obj);
889 }
890 for (id, additional_write) in additional_writes {
891 let AdditionalWrite {
892 recipient,
893 type_,
894 bytes,
895 } = additional_write;
896
897 let move_object = {
898 create_written_object(
899 vm,
900 &linkage_view,
901 protocol_config,
902 &loaded_runtime_objects,
903 id,
904 type_,
905 bytes,
906 )?
907 };
908 let object = Object::new_move(move_object, recipient, tx_digest);
909 written_objects.insert(id, object);
910 if let Some(loaded) = loaded_runtime_objects.get_mut(&id) {
911 loaded.is_modified = true;
912 }
913 }
914
915 for (id, (recipient, ty, value)) in writes {
916 let layout = vm
917 .get_runtime()
918 .type_to_type_layout(&ty)
919 .map_err(|e| convert_vm_error(e, vm, &linkage_view))?;
920 let Some(bytes) = value.simple_serialize(&layout) else {
921 invariant_violation!("Failed to deserialize already serialized Move value");
922 };
923 let move_object = {
924 create_written_object(
925 vm,
926 &linkage_view,
927 protocol_config,
928 &loaded_runtime_objects,
929 id,
930 ty,
931 bytes,
932 )?
933 };
934 let object = Object::new_move(move_object, recipient, tx_digest);
935 written_objects.insert(id, object);
936 }
937
938 for id in &by_value_shared_objects {
945 if let Some(obj) = written_objects.get(id) {
948 if !obj.is_shared() {
949 return Err(ExecutionError::new(
950 ExecutionErrorKind::SharedObjectOperationNotAllowed,
951 Some(
952 format!(
953 "Shared object operation on {id} not allowed: \
954 cannot be frozen, transferred, or wrapped"
955 )
956 .into(),
957 ),
958 ));
959 }
960 } else {
961 if !deleted_object_ids.contains(id) {
964 return Err(ExecutionError::new(
965 ExecutionErrorKind::SharedObjectOperationNotAllowed,
966 Some(
967 format!("Shared object operation on {id} not allowed: \
968 shared objects used by value must be re-shared if not deleted").into(),
969 ),
970 ));
971 }
972 }
973 }
974
975 let DenyListResult {
976 result,
977 num_non_gas_coin_owners,
978 } = state_view.check_coin_deny_list(&written_objects);
979 gas_charger.charge_coin_transfers(protocol_config, num_non_gas_coin_owners)?;
980 result?;
981
982 let user_events = user_events
983 .into_iter()
984 .map(|(module_id, tag, contents)| {
985 let package_id = ObjectId::new(module_id.address().into_bytes());
986 let module = identifier_core_to_sdk(module_id.name());
987 let sender = ref_context.borrow().sender();
988 Event {
989 package_id,
990 module,
991 sender,
992 type_: tag,
993 contents,
994 }
995 })
996 .collect();
997
998 Ok(ExecutionResults::V1(ExecutionResultsV1 {
999 written_objects,
1000 modified_objects: loaded_runtime_objects
1001 .into_iter()
1002 .filter_map(|(id, loaded)| loaded.is_modified.then_some(id))
1003 .collect(),
1004 created_object_ids: created_object_ids.into_iter().collect(),
1005 deleted_object_ids: deleted_object_ids.into_iter().collect(),
1006 user_events,
1007 }))
1008 }
1009
1010 pub fn convert_vm_error(&self, error: VMError) -> ExecutionError {
1012 crate::error::convert_vm_error(error, self.vm, &self.linkage_view)
1013 }
1014
1015 pub fn convert_type_argument_error(&self, idx: usize, error: VMError) -> ExecutionError {
1017 use iota_sdk_types::TypeArgumentError;
1018 use move_core_types::vm_status::StatusCode;
1019 match error.major_status() {
1020 StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
1021 ExecutionErrorKind::TypeArityMismatch.into()
1022 }
1023 StatusCode::TYPE_RESOLUTION_FAILURE => ExecutionErrorKind::TypeArgumentError {
1024 type_argument: idx as TypeParameterIndex,
1025 kind: TypeArgumentError::TypeNotFound,
1026 }
1027 .into(),
1028 StatusCode::CONSTRAINT_NOT_SATISFIED => ExecutionErrorKind::TypeArgumentError {
1029 type_argument: idx as TypeParameterIndex,
1030 kind: TypeArgumentError::ConstraintNotSatisfied,
1031 }
1032 .into(),
1033 _ => self.convert_vm_error(error),
1034 }
1035 }
1036
1037 fn arg_is_borrowed(&self, arg: &Arg) -> bool {
1040 self.borrowed.contains_key(arg)
1041 }
1042
1043 fn arg_is_mut_borrowed(&self, arg: &Arg) -> bool {
1046 matches!(self.borrowed.get(arg), Some(true))
1047 }
1048
1049 fn borrow_mut(
1052 &mut self,
1053 arg: Arg,
1054 usage: UsageKind,
1055 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), EitherError> {
1056 self.borrow_mut_impl(arg, Some(usage))
1057 }
1058
1059 fn borrow_mut_impl(
1062 &mut self,
1063 arg: Arg,
1064 update_last_usage: Option<UsageKind>,
1065 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), EitherError> {
1066 match arg.0 {
1067 Arg_::V1(arg) => {
1068 assert_invariant!(
1069 !self.protocol_config.normalize_ptb_arguments(),
1070 "Should not be using v1 args with normalized args"
1071 );
1072 Ok(self.borrow_mut_impl_v1(arg, update_last_usage)?)
1073 }
1074 Arg_::V2(arg) => {
1075 assert_invariant!(
1076 self.protocol_config.normalize_ptb_arguments(),
1077 "Should be using only v2 args with normalized args"
1078 );
1079 Ok(self.borrow_mut_impl_v2(arg, update_last_usage)?)
1080 }
1081 }
1082 }
1083
1084 fn borrow_mut_impl_v1(
1086 &mut self,
1087 arg: Argument,
1088 update_last_usage: Option<UsageKind>,
1089 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), CommandArgumentError>
1090 {
1091 let (metadata, result_value) = match arg {
1092 Argument::Gas => (self.gas.object_metadata.as_ref(), &mut self.gas.inner),
1093 Argument::Input(i) => {
1094 let Some(input_value) = self.inputs.get_mut(i as usize) else {
1095 return Err(CommandArgumentError::IndexOutOfBounds { index: i });
1096 };
1097 (input_value.object_metadata.as_ref(), &mut input_value.inner)
1098 }
1099 Argument::Result(i) => {
1100 let Some(command_result) = self.results.get_mut(i as usize) else {
1101 return Err(CommandArgumentError::IndexOutOfBounds { index: i });
1102 };
1103 if command_result.len() != 1 {
1104 return Err(CommandArgumentError::InvalidResultArity { result: i });
1105 }
1106 (None, &mut command_result[0])
1107 }
1108 Argument::NestedResult(i, j) => {
1109 let Some(command_result) = self.results.get_mut(i as usize) else {
1110 return Err(CommandArgumentError::IndexOutOfBounds { index: i });
1111 };
1112 let Some(result_value) = command_result.get_mut(j as usize) else {
1113 return Err(CommandArgumentError::SecondaryIndexOutOfBounds {
1114 result: i,
1115 subresult: j,
1116 });
1117 };
1118 (None, result_value)
1119 }
1120 _ => {
1121 unimplemented!("a new Argument enum variant was added and needs to be handled")
1122 }
1123 };
1124 if let Some(usage) = update_last_usage {
1125 result_value.last_usage_kind = Some(usage);
1126 }
1127 Ok((metadata, &mut result_value.value))
1128 }
1129
1130 fn borrow_mut_impl_v2(
1132 &mut self,
1133 arg: NormalizedArg,
1134 update_last_usage: Option<UsageKind>,
1135 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), ExecutionError> {
1136 let (metadata, result_value) = match arg {
1137 NormalizedArg::GasCoin => (self.gas.object_metadata.as_ref(), &mut self.gas.inner),
1138 NormalizedArg::Input(i) => {
1139 let input_value = self
1140 .inputs
1141 .get_mut(i as usize)
1142 .ok_or_else(|| make_invariant_violation!("bounds already checked"))?;
1143 (input_value.object_metadata.as_ref(), &mut input_value.inner)
1144 }
1145 NormalizedArg::Result(i, j) => {
1146 let result_value = self
1147 .results
1148 .get_mut(i as usize)
1149 .ok_or_else(|| make_invariant_violation!("bounds already checked"))?
1150 .get_mut(j as usize)
1151 .ok_or_else(|| make_invariant_violation!("bounds already checked"))?;
1152 (None, result_value)
1153 }
1154 };
1155 if let Some(usage) = update_last_usage {
1156 result_value.last_usage_kind = Some(usage);
1157 }
1158 Ok((metadata, &mut result_value.value))
1159 }
1160
1161 pub(crate) fn execute_function_bypass_visibility(
1166 &mut self,
1167 module: &ModuleId,
1168 function_name: &IdentStr,
1169 ty_args: Vec<Type>,
1170 args: Vec<impl Borrow<[u8]>>,
1171 tracer: &mut Option<MoveTraceBuilder>,
1172 ) -> VMResult<SerializedReturnValues> {
1173 let gas_status = self.gas_charger.move_gas_status_mut();
1174 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1175 self.vm.get_runtime().execute_function_bypass_visibility(
1176 module,
1177 function_name,
1178 ty_args,
1179 args,
1180 &mut data_store,
1181 &mut IotaGasMeter(gas_status),
1182 &mut self.native_extensions,
1183 tracer.as_mut(),
1184 )
1185 }
1186
1187 pub(crate) fn load_function(
1192 &mut self,
1193 module_id: &ModuleId,
1194 function_name: &IdentStr,
1195 type_arguments: &[Type],
1196 ) -> VMResult<LoadedFunctionInstantiation> {
1197 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1198 self.vm.get_runtime().load_function(
1199 module_id,
1200 function_name,
1201 type_arguments,
1202 &mut data_store,
1203 )
1204 }
1205
1206 pub(crate) fn make_object_value(
1211 &mut self,
1212 type_: StructTag,
1213 used_in_non_entry_move_call: bool,
1214 contents: &[u8],
1215 ) -> Result<ObjectValue, ExecutionError> {
1216 make_object_value(
1217 self.vm,
1218 &mut self.linkage_view,
1219 &self.new_packages,
1220 type_,
1221 used_in_non_entry_move_call,
1222 contents,
1223 )
1224 }
1225
1226 pub fn publish_module_bundle(
1231 &mut self,
1232 modules: Vec<Vec<u8>>,
1233 sender: AccountAddress,
1234 ) -> VMResult<()> {
1235 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1238 self.vm.get_runtime().publish_module_bundle(
1239 modules,
1240 sender,
1241 &mut data_store,
1242 &mut IotaGasMeter(self.gas_charger.move_gas_status_mut()),
1243 )
1244 }
1245 }
1246
1247 impl TypeTagResolver for ExecutionContext<'_, '_, '_> {
1248 fn get_type_tag(&self, type_: &Type) -> Result<TypeTag, ExecutionError> {
1251 self.vm
1252 .get_runtime()
1253 .get_type_tag(type_)
1254 .map_err(|e| self.convert_vm_error(e))
1255 .map(|tt| type_tag_core_to_sdk(&tt))
1256 }
1257 }
1258
1259 fn package_for_linkage(
1263 linkage_view: &LinkageView,
1264 package_id: ObjectId,
1265 ) -> VMResult<PackageObject> {
1266 use move_binary_format::errors::PartialVMError;
1267 use move_core_types::vm_status::StatusCode;
1268
1269 match linkage_view.get_package_object(&package_id) {
1270 Ok(Some(package)) => Ok(package),
1271 Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1272 .with_message(format!("Cannot find link context {package_id} in store"))
1273 .finish(Location::Undefined)),
1274 Err(err) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1275 .with_message(format!(
1276 "Error loading link context {package_id} from store: {err}"
1277 ))
1278 .finish(Location::Undefined)),
1279 }
1280 }
1281
1282 pub fn load_type_from_struct(
1288 vm: &MoveVM,
1289 linkage_view: &mut LinkageView,
1290 new_packages: &[MovePackage],
1291 struct_tag: &StructTag,
1292 ) -> VMResult<Type> {
1293 fn verification_error<T>(code: StatusCode) -> VMResult<T> {
1294 Err(PartialVMError::new(code).finish(Location::Undefined))
1295 }
1296
1297 let defining_id = struct_tag.address().into();
1299 let package = package_for_linkage(linkage_view, defining_id)?;
1300
1301 let original_address = linkage_view
1304 .set_linkage(package.move_package())
1305 .map_err(|e| {
1306 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1307 .with_message(e.to_string())
1308 .finish(Location::Undefined)
1309 })?;
1310
1311 let runtime_id = ModuleId::new(
1312 original_address,
1313 identifier_sdk_to_core(struct_tag.module()),
1314 );
1315 let data_store = IotaDataStore::new(linkage_view, new_packages);
1316 let res = vm.get_runtime().load_type(
1317 &runtime_id,
1318 IdentStr::new(struct_tag.name().as_str()).unwrap(),
1319 &data_store,
1320 );
1321 linkage_view.reset_linkage();
1322 let (idx, struct_type) = res?;
1323
1324 let type_param_constraints = struct_type.type_param_constraints();
1326 if type_param_constraints.len() != struct_tag.type_params().len() {
1327 return verification_error(StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH);
1328 }
1329
1330 if struct_tag.type_params().is_empty() {
1331 Ok(Type::Datatype(idx))
1332 } else {
1333 let loaded_type_params = struct_tag
1334 .type_params()
1335 .iter()
1336 .map(|type_param| load_type(vm, linkage_view, new_packages, type_param))
1337 .collect::<VMResult<Vec<_>>>()?;
1338
1339 for (constraint, param) in type_param_constraints.zip(&loaded_type_params) {
1341 let abilities = vm.get_runtime().get_type_abilities(param)?;
1342 if !constraint.is_subset(abilities) {
1343 return verification_error(StatusCode::CONSTRAINT_NOT_SATISFIED);
1344 }
1345 }
1346
1347 Ok(Type::DatatypeInstantiation(Box::new((
1348 idx,
1349 loaded_type_params,
1350 ))))
1351 }
1352 }
1353
1354 pub fn load_type(
1358 vm: &MoveVM,
1359 linkage_view: &mut LinkageView,
1360 new_packages: &[MovePackage],
1361 type_tag: &TypeTag,
1362 ) -> VMResult<Type> {
1363 Ok(match type_tag {
1364 TypeTag::Bool => Type::Bool,
1365 TypeTag::U8 => Type::U8,
1366 TypeTag::U16 => Type::U16,
1367 TypeTag::U32 => Type::U32,
1368 TypeTag::U64 => Type::U64,
1369 TypeTag::U128 => Type::U128,
1370 TypeTag::U256 => Type::U256,
1371 TypeTag::Address => Type::Address,
1372 TypeTag::Signer => Type::Signer,
1373
1374 TypeTag::Vector(inner) => {
1375 Type::Vector(Box::new(load_type(vm, linkage_view, new_packages, inner)?))
1376 }
1377 TypeTag::Struct(struct_tag) => {
1378 return load_type_from_struct(vm, linkage_view, new_packages, struct_tag);
1379 }
1380 })
1381 }
1382
1383 pub(crate) fn make_object_value(
1390 vm: &MoveVM,
1391 linkage_view: &mut LinkageView,
1392 new_packages: &[MovePackage],
1393 type_: StructTag,
1394 used_in_non_entry_move_call: bool,
1395 contents: &[u8],
1396 ) -> Result<ObjectValue, ExecutionError> {
1397 let contents = if type_.is_coin() {
1398 let Ok(coin) = Coin::from_bcs_bytes(contents) else {
1399 invariant_violation!("Could not deserialize a coin")
1400 };
1401 ObjectContents::Coin(coin)
1402 } else {
1403 ObjectContents::Raw(contents.to_vec())
1404 };
1405
1406 let type_ = load_type_from_struct(vm, linkage_view, new_packages, &type_)
1407 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1408 let abilities = vm
1409 .get_runtime()
1410 .get_type_abilities(&type_)
1411 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1412 let has_public_transfer = abilities.has_store();
1413 Ok(ObjectValue {
1414 type_,
1415 has_public_transfer,
1416 used_in_non_entry_move_call,
1417 contents,
1418 })
1419 }
1420
1421 impl Arg {
1422 fn is_gas_coin(&self) -> bool {
1423 match self {
1425 Arg(Arg_::V1(a)) => matches!(a, Argument::Gas),
1426 Arg(Arg_::V2(n)) => matches!(n, NormalizedArg::GasCoin),
1427 }
1428 }
1429 }
1430
1431 impl From<Arg> for Argument {
1432 fn from(arg: Arg) -> Self {
1433 match arg.0 {
1434 Arg_::V1(a) => a,
1435 Arg_::V2(normalized) => match normalized {
1436 NormalizedArg::GasCoin => Argument::Gas,
1437 NormalizedArg::Input(i) => Argument::Input(i),
1438 NormalizedArg::Result(i, j) => Argument::NestedResult(i, j),
1439 },
1440 }
1441 }
1442 }
1443
1444 pub(crate) fn value_from_object(
1449 vm: &MoveVM,
1450 linkage_view: &mut LinkageView,
1451 new_packages: &[MovePackage],
1452 object: &Object,
1453 ) -> Result<ObjectValue, ExecutionError> {
1454 let ObjectInner {
1455 data: ObjectData::Struct(object),
1456 ..
1457 } = object.as_inner()
1458 else {
1459 invariant_violation!("Expected a Move object");
1460 };
1461
1462 let used_in_non_entry_move_call = false;
1463 make_object_value(
1464 vm,
1465 linkage_view,
1466 new_packages,
1467 object.struct_tag().clone(),
1468 used_in_non_entry_move_call,
1469 object.contents(),
1470 )
1471 }
1472
1473 fn load_object(
1475 vm: &MoveVM,
1476 state_view: &dyn ExecutionState,
1477 linkage_view: &mut LinkageView,
1478 new_packages: &[MovePackage],
1479 input_object_map: &mut BTreeMap<ObjectId, object_runtime::InputObject>,
1480 override_as_immutable: bool,
1481 id: ObjectId,
1482 ) -> Result<InputValue, ExecutionError> {
1483 let Some(obj) = state_view.read_object(&id) else {
1484 invariant_violation!("Object {} does not exist yet", id);
1486 };
1487 assert_invariant!(
1489 !override_as_immutable || matches!(obj.owner, Owner::Shared(_)),
1490 "override_as_immutable should only be set for shared objects"
1491 );
1492 let is_mutable_input = match obj.owner {
1493 Owner::Address(_) => true,
1494 Owner::Shared(_) => !override_as_immutable,
1495 Owner::Immutable => false,
1496 Owner::Object(_) => {
1497 invariant_violation!("Object-owned objects cannot be inputs")
1499 }
1500 _ => unimplemented!("a new Owner enum variant was added and needs to be handled"),
1501 };
1502 let owner = obj.owner;
1503 let version = obj.version();
1504 let object_metadata = InputObjectMetadata::InputObject {
1505 id,
1506 is_mutable_input,
1507 owner,
1508 version,
1509 };
1510 let obj_value = value_from_object(vm, linkage_view, new_packages, obj)?;
1511 let contained_uids = {
1512 let fully_annotated_layout = vm
1513 .get_runtime()
1514 .type_to_fully_annotated_layout(&obj_value.type_)
1515 .map_err(|e| convert_vm_error(e, vm, linkage_view))?;
1516 let mut bytes = vec![];
1517 obj_value.write_bcs_bytes(&mut bytes, None)?;
1518 match get_all_uids(&fully_annotated_layout, &bytes) {
1519 Err(e) => {
1520 invariant_violation!("Unable to retrieve UIDs for object. Got error: {e}")
1521 }
1522 Ok(uids) => uids,
1523 }
1524 };
1525 let runtime_input = object_runtime::InputObject {
1526 contained_uids,
1527 owner,
1528 version,
1529 };
1530 let prev = input_object_map.insert(id, runtime_input);
1531 assert_invariant!(prev.is_none(), "Duplicate input object {}", id);
1533 Ok(InputValue::new_object(object_metadata, obj_value))
1534 }
1535
1536 fn load_call_arg(
1538 vm: &MoveVM,
1539 state_view: &dyn ExecutionState,
1540 linkage_view: &mut LinkageView,
1541 new_packages: &[MovePackage],
1542 input_object_map: &mut BTreeMap<ObjectId, object_runtime::InputObject>,
1543 call_arg: CallArg,
1544 ) -> Result<InputValue, ExecutionError> {
1545 Ok(match call_arg {
1546 CallArg::Pure(value) => InputValue::new_raw(RawValueType::Any, value),
1547 other => load_object_arg(
1548 vm,
1549 state_view,
1550 linkage_view,
1551 new_packages,
1552 input_object_map,
1553 other,
1554 )?,
1555 })
1556 }
1557
1558 fn load_object_arg(
1561 vm: &MoveVM,
1562 state_view: &dyn ExecutionState,
1563 linkage_view: &mut LinkageView,
1564 new_packages: &[MovePackage],
1565 input_object_map: &mut BTreeMap<ObjectId, object_runtime::InputObject>,
1566 obj_arg: CallArg,
1567 ) -> Result<InputValue, ExecutionError> {
1568 match obj_arg {
1569 CallArg::ImmutableOrOwned(object_ref) => load_object(
1570 vm,
1571 state_view,
1572 linkage_view,
1573 new_packages,
1574 input_object_map,
1575 false,
1577 object_ref.object_id,
1578 ),
1579 CallArg::Shared(SharedObjectReference {
1580 object_id: id,
1581 mutable,
1582 ..
1583 }) => load_object(
1584 vm,
1585 state_view,
1586 linkage_view,
1587 new_packages,
1588 input_object_map,
1589 !mutable,
1591 id,
1592 ),
1593 CallArg::Receiving(object_ref) => Ok(InputValue::new_receiving_object(
1594 object_ref.object_id,
1595 object_ref.version,
1596 )),
1597 CallArg::Pure(_) => Err(ExecutionError::invariant_violation(
1598 "unexpected pure CallArg in load_object_arg",
1599 )),
1600 _ => Err(ExecutionError::invariant_violation(
1601 "a new CallArg enum variant was added and needs to be handled",
1602 )),
1603 }
1604 }
1605
1606 fn add_additional_write(
1608 additional_writes: &mut BTreeMap<ObjectId, AdditionalWrite>,
1609 owner: Owner,
1610 object_value: ObjectValue,
1611 ) -> Result<(), ExecutionError> {
1612 let ObjectValue {
1613 type_, contents, ..
1614 } = object_value;
1615 let bytes = match contents {
1616 ObjectContents::Coin(coin) => coin.to_bcs_bytes(),
1617 ObjectContents::Raw(bytes) => bytes,
1618 };
1619 let object_id =
1620 ObjectId::from_bytes(bytes.get(..ObjectId::LENGTH).ok_or_else(|| {
1621 ExecutionError::invariant_violation("No id for Raw object bytes")
1622 })?)
1623 .expect("ObjectId::LENGTH bytes is always a valid ObjectId");
1624 let additional_write = AdditionalWrite {
1625 recipient: owner,
1626 type_,
1627 bytes,
1628 };
1629 additional_writes.insert(object_id, additional_write);
1630 Ok(())
1631 }
1632
1633 fn refund_max_gas_budget(
1637 additional_writes: &mut BTreeMap<ObjectId, AdditionalWrite>,
1638 gas_charger: &mut GasCharger,
1639 gas_id: ObjectId,
1640 ) -> Result<(), ExecutionError> {
1641 let Some(AdditionalWrite { bytes, .. }) = additional_writes.get_mut(&gas_id) else {
1642 invariant_violation!("Gas object cannot be wrapped or destroyed")
1643 };
1644 let Ok(mut coin) = Coin::from_bcs_bytes(bytes) else {
1645 invariant_violation!("Gas object must be a coin")
1646 };
1647 let Some(new_balance) = coin.balance.value().checked_add(gas_charger.gas_budget()) else {
1648 return Err(ExecutionError::new_with_source(
1649 ExecutionErrorKind::CoinBalanceOverflow,
1650 "Gas coin too large after returning the max gas budget",
1651 ));
1652 };
1653 coin.balance = Balance::new(new_balance);
1654 *bytes = coin.to_bcs_bytes();
1655 Ok(())
1656 }
1657
1658 fn create_written_object(
1660 vm: &MoveVM,
1661 linkage_view: &LinkageView,
1662 protocol_config: &ProtocolConfig,
1663 objects_modified_at: &BTreeMap<ObjectId, LoadedRuntimeObject>,
1664 id: ObjectId,
1665 type_: Type,
1666 contents: Vec<u8>,
1667 ) -> Result<MoveObject, ExecutionError> {
1668 debug_assert_eq!(
1669 id,
1670 ObjectId::from_bytes(&contents[..ObjectId::LENGTH])
1671 .expect("object contents should start with an id")
1672 );
1673 let old_obj_ver = objects_modified_at
1674 .get(&id)
1675 .map(|obj: &LoadedRuntimeObject| obj.version);
1676
1677 let type_tag = type_tag_core_to_sdk(
1678 &vm.get_runtime()
1679 .get_type_tag(&type_)
1680 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?,
1681 );
1682
1683 let struct_tag = match type_tag {
1684 TypeTag::Struct(inner) => *inner,
1685 _ => invariant_violation!("Non struct type for object"),
1686 };
1687 MoveObject::new_from_execution(
1688 struct_tag,
1689 old_obj_ver.unwrap_or_default(),
1690 contents,
1691 protocol_config,
1692 )
1693 }
1694
1695 pub(crate) struct IotaDataStore<'state, 'a> {
1703 linkage_view: &'a LinkageView<'state>,
1704 new_packages: &'a [MovePackage],
1705 }
1706
1707 impl<'state, 'a> IotaDataStore<'state, 'a> {
1708 pub(crate) fn new(
1709 linkage_view: &'a LinkageView<'state>,
1710 new_packages: &'a [MovePackage],
1711 ) -> Self {
1712 Self {
1713 linkage_view,
1714 new_packages,
1715 }
1716 }
1717
1718 fn get_module(&self, module_id: &ModuleId) -> Option<&Vec<u8>> {
1719 for package in self.new_packages {
1720 if package.id != ObjectId::from(module_id.address().into_bytes()) {
1721 continue;
1722 }
1723
1724 let module = package.get_module(&identifier_core_to_sdk(module_id.name()));
1725
1726 if module.is_some() {
1727 return module;
1728 }
1729 }
1730 None
1731 }
1732 }
1733
1734 impl DataStore for IotaDataStore<'_, '_> {
1738 fn link_context(&self) -> AccountAddress {
1739 self.linkage_view.link_context()
1740 }
1741
1742 fn relocate(&self, module_id: &ModuleId) -> PartialVMResult<ModuleId> {
1743 self.linkage_view.relocate(module_id).map_err(|err| {
1744 PartialVMError::new(StatusCode::LINKER_ERROR)
1745 .with_message(format!("Error relocating {module_id}: {err:?}"))
1746 })
1747 }
1748
1749 fn defining_module(
1750 &self,
1751 runtime_id: &ModuleId,
1752 struct_: &IdentStr,
1753 ) -> PartialVMResult<ModuleId> {
1754 self.linkage_view
1755 .defining_module(runtime_id, struct_)
1756 .map_err(|err| {
1757 PartialVMError::new(StatusCode::LINKER_ERROR).with_message(format!(
1758 "Error finding defining module for {runtime_id}::{struct_}: {err:?}"
1759 ))
1760 })
1761 }
1762
1763 fn load_module(&self, module_id: &ModuleId) -> VMResult<Vec<u8>> {
1764 if let Some(bytes) = self.get_module(module_id) {
1765 return Ok(bytes.clone());
1766 }
1767 match self.linkage_view.get_module(module_id) {
1768 Ok(Some(bytes)) => Ok(bytes),
1769 Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1770 .with_message(format!("Cannot find {module_id:?} in data cache"))
1771 .finish(Location::Undefined)),
1772 Err(err) => {
1773 let msg = format!("Unexpected storage error: {err:?}");
1774 Err(
1775 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1776 .with_message(msg)
1777 .finish(Location::Undefined),
1778 )
1779 }
1780 }
1781 }
1782
1783 fn publish_module(&mut self, _module_id: &ModuleId, _blob: Vec<u8>) -> VMResult<()> {
1784 Ok(())
1787 }
1788 }
1789
1790 enum EitherError {
1791 CommandArgument(CommandArgumentError),
1792 Execution(ExecutionError),
1793 }
1794
1795 impl From<ExecutionError> for EitherError {
1796 fn from(e: ExecutionError) -> Self {
1797 EitherError::Execution(e)
1798 }
1799 }
1800
1801 impl From<CommandArgumentError> for EitherError {
1802 fn from(e: CommandArgumentError) -> Self {
1803 EitherError::CommandArgument(e)
1804 }
1805 }
1806
1807 impl EitherError {
1808 fn into_execution_error(self, command_index: usize) -> ExecutionError {
1809 match self {
1810 EitherError::CommandArgument(e) => command_argument_error(e, command_index),
1811 EitherError::Execution(e) => e,
1812 }
1813 }
1814 }
1815}