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, derive_package_metadata_id},
29 object::{Data, MoveObject, Object, ObjectInner, Owner},
30 storage::{BackingPackageStore, DenyListResult, PackageObject},
31 transaction::{Argument, CallArg, ObjectArg},
32 };
33 use move_binary_format::{
34 CompiledModule,
35 errors::{Location, PartialVMError, PartialVMResult, VMError, VMResult},
36 file_format::{CodeOffset, FunctionDefinitionIndex, TypeParameterIndex},
37 };
38 use move_core_types::{
39 account_address::AccountAddress,
40 identifier::IdentStr,
41 language_storage::{ModuleId, StructTag, TypeTag},
42 resolver::ModuleResolver,
43 vm_status::StatusCode,
44 };
45 use move_trace_format::format::MoveTraceBuilder;
46 use move_vm_runtime::{
47 move_vm::MoveVM,
48 native_extensions::NativeContextExtensions,
49 session::{LoadedFunctionInstantiation, SerializedReturnValues},
50 };
51 use move_vm_types::{data_store::DataStore, loaded_data::runtime_types::Type};
52 use tracing::instrument;
53
54 use crate::{
55 adapter::new_native_extensions,
56 error::convert_vm_error,
57 execution_mode::ExecutionMode,
58 execution_value::{
59 CommandKind, ExecutionState, InputObjectMetadata, InputValue, ObjectContents,
60 ObjectValue, RawValueType, ResultValue, TryFromValue, UsageKind, Value,
61 },
62 gas_charger::GasCharger,
63 gas_meter::IotaGasMeter,
64 programmable_transactions::linkage_view::LinkageView,
65 type_resolver::TypeTagResolver,
66 };
67
68 pub struct ExecutionContext<'vm, 'state, 'a> {
70 pub protocol_config: &'a ProtocolConfig,
72 pub metrics: Arc<LimitsMetrics>,
74 pub vm: &'vm MoveVM,
76 pub linkage_view: LinkageView<'state>,
78 pub native_extensions: NativeContextExtensions<'state>,
79 pub state_view: &'state dyn ExecutionState,
81 pub tx_context: &'a mut TxContext,
84 pub gas_charger: &'a mut GasCharger,
86 additional_transfers: Vec<(Owner, ObjectValue)>,
88 new_packages: Vec<MovePackage>,
90 user_events: Vec<(ModuleId, StructTag, Vec<u8>)>,
92 gas: InputValue,
95 inputs: Vec<InputValue>,
98 results: Vec<Vec<ResultValue>>,
103 borrowed: HashMap<Arg, bool>,
107 }
108
109 struct AdditionalWrite {
112 recipient: Owner,
114 type_: Type,
116 bytes: Vec<u8>,
118 }
119
120 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
121 pub struct Arg(Arg_);
122
123 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
124 enum Arg_ {
125 V1(Argument),
126 V2(NormalizedArg),
127 }
128
129 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
130 enum NormalizedArg {
131 GasCoin,
132 Input(u16),
133 Result(u16, u16),
134 }
135
136 impl<'vm, 'state, 'a> ExecutionContext<'vm, 'state, 'a> {
137 #[instrument(name = "ExecutionContext::new", level = "trace", skip_all)]
144 pub fn new(
145 protocol_config: &'a ProtocolConfig,
146 metrics: Arc<LimitsMetrics>,
147 vm: &'vm MoveVM,
148 state_view: &'state dyn ExecutionState,
149 tx_context: &'a mut TxContext,
150 gas_charger: &'a mut GasCharger,
151 inputs: Vec<CallArg>,
152 ) -> Result<Self, ExecutionError>
153 where
154 'a: 'state,
155 {
156 let mut linkage_view = LinkageView::new(Box::new(state_view.as_iota_resolver()));
157 let mut input_object_map = BTreeMap::new();
158 let inputs = inputs
159 .into_iter()
160 .map(|call_arg| {
161 load_call_arg(
162 vm,
163 state_view,
164 &mut linkage_view,
165 &[],
166 &mut input_object_map,
167 call_arg,
168 )
169 })
170 .collect::<Result<_, ExecutionError>>()?;
171 let gas = if let Some(gas_coin) = gas_charger.gas_coin() {
172 let mut gas = load_object(
173 vm,
174 state_view,
175 &mut linkage_view,
176 &[],
177 &mut input_object_map,
178 false,
180 gas_coin,
181 )?;
182 let Some(Value::Object(ObjectValue {
186 contents: ObjectContents::Coin(coin),
187 ..
188 })) = &mut gas.inner.value
189 else {
190 invariant_violation!("Gas object should be a populated coin")
191 };
192
193 let max_gas_in_balance = gas_charger.gas_budget();
194 let Some(new_balance) = coin.balance.value().checked_sub(max_gas_in_balance) else {
195 invariant_violation!(
196 "Transaction input checker should check that there is enough gas"
197 );
198 };
199 coin.balance = Balance::new(new_balance);
200 gas
201 } else {
202 InputValue {
203 object_metadata: None,
204 inner: ResultValue {
205 last_usage_kind: None,
206 value: None,
207 },
208 }
209 };
210 let native_extensions = new_native_extensions(
211 state_view.as_child_resolver(),
212 input_object_map,
213 !gas_charger.is_unmetered(),
214 protocol_config,
215 metrics.clone(),
216 tx_context.epoch(),
217 );
218
219 #[skip_checked_arithmetic]
221 move_vm_profiler::tracing_feature_enabled! {
222 use move_vm_profiler::GasProfiler;
223 use move_vm_types::gas::GasMeter;
224
225 let tx_digest = tx_context.digest();
226 let remaining_gas: u64 =
227 move_vm_types::gas::GasMeter::remaining_gas(&IotaGasMeter(gas_charger.move_gas_status_mut()))
228 .into();
229 IotaGasMeter(gas_charger.move_gas_status_mut())
230 .set_profiler(GasProfiler::init(
231 &vm.config().profiler_config,
232 format!("{tx_digest}"),
233 remaining_gas,
234 ));
235 }
236
237 Ok(Self {
238 protocol_config,
239 metrics,
240 vm,
241 linkage_view,
242 native_extensions,
243 state_view,
244 tx_context,
245 gas_charger,
246 gas,
247 inputs,
248 results: vec![],
249 additional_transfers: vec![],
250 new_packages: vec![],
251 user_events: vec![],
252 borrowed: HashMap::new(),
253 })
254 }
255
256 pub fn object_runtime(&self) -> Result<&ObjectRuntime<'_>, ExecutionError> {
257 self.native_extensions
258 .get::<ObjectRuntime>()
259 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))
260 }
261
262 pub fn fresh_id(&mut self) -> Result<ObjectID, ExecutionError> {
264 let object_id = self.tx_context.fresh_id();
265 self.native_extensions
266 .get_mut()
267 .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.new_id(object_id))
268 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
269 Ok(object_id)
270 }
271
272 pub(crate) fn package_derived_metadata_id(
274 &mut self,
275 package_storage_id: ObjectID,
276 ) -> Result<ObjectID, ExecutionError> {
277 let object_id = derive_package_metadata_id(package_storage_id);
278
279 self.native_extensions
280 .get_mut()
281 .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.new_id(object_id))
282 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
283 Ok(object_id)
284 }
285
286 pub fn delete_id(&mut self, object_id: ObjectID) -> Result<(), ExecutionError> {
288 self.native_extensions
289 .get_mut()
290 .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.delete_id(object_id))
291 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))
292 }
293
294 pub fn set_link_context(
298 &mut self,
299 package_id: ObjectID,
300 ) -> Result<AccountAddress, ExecutionError> {
301 if self.linkage_view.has_linkage(package_id) {
302 return Ok(self
304 .linkage_view
305 .original_package_id()
306 .unwrap_or(*package_id));
307 }
308
309 let package = package_for_linkage(&self.linkage_view, package_id)
310 .map_err(|e| self.convert_vm_error(e))?;
311
312 self.linkage_view.set_linkage(package.move_package())
313 }
314
315 pub fn load_type(&mut self, type_tag: &TypeTag) -> VMResult<Type> {
317 load_type(
318 self.vm,
319 &mut self.linkage_view,
320 &self.new_packages,
321 type_tag,
322 )
323 }
324
325 pub fn load_type_from_struct(&mut self, struct_tag: &StructTag) -> VMResult<Type> {
327 load_type_from_struct(
328 self.vm,
329 &mut self.linkage_view,
330 &self.new_packages,
331 struct_tag,
332 )
333 }
334
335 pub fn take_user_events(
338 &mut self,
339 module_id: &ModuleId,
340 function: FunctionDefinitionIndex,
341 last_offset: CodeOffset,
342 ) -> Result<(), ExecutionError> {
343 let events = self
344 .native_extensions
345 .get_mut()
346 .map(|object_runtime: &mut ObjectRuntime| object_runtime.take_user_events())
347 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
348 let num_events = self.user_events.len() + events.len();
349 let max_events = self.protocol_config.max_num_event_emit();
350 if num_events as u64 > max_events {
351 let err = max_event_error(max_events)
352 .at_code_offset(function, last_offset)
353 .finish(Location::Module(module_id.clone()));
354 return Err(self.convert_vm_error(err));
355 }
356 let new_events = events
357 .into_iter()
358 .map(|(ty, tag, value)| {
359 let layout = self
360 .vm
361 .get_runtime()
362 .type_to_type_layout(&ty)
363 .map_err(|e| self.convert_vm_error(e))?;
364 let Some(bytes) = value.simple_serialize(&layout) else {
365 invariant_violation!("Failed to deserialize already serialized Move value");
366 };
367 Ok((module_id.clone(), tag, bytes))
368 })
369 .collect::<Result<Vec<_>, ExecutionError>>()?;
370 self.user_events.extend(new_events);
371 Ok(())
372 }
373
374 pub fn splat_args<Items: IntoIterator<Item = Argument>>(
380 &self,
381 start_idx: usize,
382 args: Items,
383 ) -> Result<Vec<Arg>, ExecutionError>
384 where
385 Items::IntoIter: ExactSizeIterator,
386 {
387 if !self.protocol_config.normalize_ptb_arguments() {
388 Ok(args.into_iter().map(|arg| Arg(Arg_::V1(arg))).collect())
389 } else {
390 let args = args.into_iter();
391 let _args_len = args.len();
392 let mut res = vec![];
393 for (arg_idx, arg) in args.enumerate() {
394 self.splat_arg(&mut res, arg)
395 .map_err(|e| e.into_execution_error(start_idx + arg_idx))?;
396 }
397 debug_assert_eq!(res.len(), _args_len);
398 Ok(res)
399 }
400 }
401
402 fn splat_arg(&self, res: &mut Vec<Arg>, arg: Argument) -> Result<(), EitherError> {
403 match arg {
404 Argument::GasCoin => res.push(Arg(Arg_::V2(NormalizedArg::GasCoin))),
405 Argument::Input(i) => {
406 if i as usize >= self.inputs.len() {
407 return Err(CommandArgumentError::IndexOutOfBounds { idx: i }.into());
408 }
409 res.push(Arg(Arg_::V2(NormalizedArg::Input(i))))
410 }
411 Argument::NestedResult(i, j) => {
412 let Some(command_result) = self.results.get(i as usize) else {
413 return Err(CommandArgumentError::IndexOutOfBounds { idx: i }.into());
414 };
415 if j as usize >= command_result.len() {
416 return Err(CommandArgumentError::SecondaryIndexOutOfBounds {
417 result_idx: i,
418 secondary_idx: j,
419 }
420 .into());
421 };
422 res.push(Arg(Arg_::V2(NormalizedArg::Result(i, j))))
423 }
424 Argument::Result(i) => {
425 let Some(result) = self.results.get(i as usize) else {
426 return Err(CommandArgumentError::IndexOutOfBounds { idx: i }.into());
427 };
428 let Ok(len): Result<u16, _> = result.len().try_into() else {
429 invariant_violation!("Result of length greater than u16::MAX");
430 };
431 if len != 1 {
432 return Err(
434 CommandArgumentError::InvalidResultArity { result_idx: i }.into()
435 );
436 }
437 res.extend((0..len).map(|j| Arg(Arg_::V2(NormalizedArg::Result(i, j)))))
438 }
439 }
440 Ok(())
441 }
442
443 pub fn one_arg(
444 &self,
445 command_arg_idx: usize,
446 arg: Argument,
447 ) -> Result<Arg, ExecutionError> {
448 let args = self.splat_args(command_arg_idx, vec![arg])?;
449 let Ok([arg]): Result<[Arg; 1], _> = args.try_into() else {
450 return Err(command_argument_error(
451 CommandArgumentError::InvalidArgumentArity,
452 command_arg_idx,
453 ));
454 };
455 Ok(arg)
456 }
457
458 pub fn by_value_arg<V: TryFromValue>(
464 &mut self,
465 command_kind: CommandKind<'_>,
466 arg_idx: usize,
467 arg: Arg,
468 ) -> Result<V, ExecutionError> {
469 self.by_value_arg_(command_kind, arg)
470 .map_err(|e| e.into_execution_error(arg_idx))
471 }
472 fn by_value_arg_<V: TryFromValue>(
473 &mut self,
474 command_kind: CommandKind<'_>,
475 arg: Arg,
476 ) -> Result<V, EitherError> {
477 let is_borrowed = self.arg_is_borrowed(&arg);
478 let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::ByValue)?;
479 let is_copyable = if let Some(val) = val_opt {
480 val.is_copyable()
481 } else {
482 return Err(CommandArgumentError::InvalidValueUsage.into());
483 };
484 if !is_copyable && is_borrowed {
490 return Err(CommandArgumentError::InvalidValueUsage.into());
491 }
492 if arg.is_gas_coin() && !matches!(command_kind, CommandKind::TransferObjects) {
494 return Err(CommandArgumentError::InvalidGasCoinUsage.into());
495 }
496 if matches!(
498 input_metadata_opt,
499 Some(InputObjectMetadata::InputObject {
500 owner: Owner::Immutable,
501 ..
502 })
503 ) {
504 return Err(CommandArgumentError::InvalidObjectByValue.into());
505 }
506
507 if matches!(
509 input_metadata_opt,
510 Some(InputObjectMetadata::InputObject {
511 is_mutable_input: false,
512 ..
513 })
514 ) {
515 return Err(CommandArgumentError::InvalidObjectByValue.into());
516 }
517
518 let val = if is_copyable {
519 val_opt.as_ref().unwrap().clone()
520 } else {
521 val_opt.take().unwrap()
522 };
523 Ok(V::try_from_value(val)?)
524 }
525
526 pub fn borrow_arg_mut<V: TryFromValue>(
533 &mut self,
534 arg_idx: usize,
535 arg: Arg,
536 ) -> Result<V, ExecutionError> {
537 self.borrow_arg_mut_(arg)
538 .map_err(|e| e.into_execution_error(arg_idx))
539 }
540 fn borrow_arg_mut_<V: TryFromValue>(&mut self, arg: Arg) -> Result<V, EitherError> {
541 if self.arg_is_borrowed(&arg) {
543 return Err(CommandArgumentError::InvalidValueUsage.into());
544 }
545 self.borrowed.insert(arg, true);
546 let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowMut)?;
547 let is_copyable = if let Some(val) = val_opt {
548 val.is_copyable()
549 } else {
550 return Err(CommandArgumentError::InvalidValueUsage.into());
552 };
553 if let Some(InputObjectMetadata::InputObject {
554 is_mutable_input: false,
555 ..
556 }) = input_metadata_opt
557 {
558 return Err(CommandArgumentError::InvalidObjectByMutRef.into());
559 }
560 let val = if is_copyable {
563 val_opt.as_ref().unwrap().clone()
564 } else {
565 val_opt.take().unwrap()
566 };
567 Ok(V::try_from_value(val)?)
568 }
569
570 pub fn borrow_arg<V: TryFromValue>(
575 &mut self,
576 arg_idx: usize,
577 arg: Arg,
578 type_: &Type,
579 ) -> Result<V, ExecutionError> {
580 self.borrow_arg_(arg, type_)
581 .map_err(|e| e.into_execution_error(arg_idx))
582 }
583 fn borrow_arg_<V: TryFromValue>(
584 &mut self,
585 arg: Arg,
586 arg_type: &Type,
587 ) -> Result<V, EitherError> {
588 if self.arg_is_mut_borrowed(&arg) {
592 return Err(CommandArgumentError::InvalidValueUsage.into());
593 }
594 self.borrowed.insert(arg, false);
595 let (_input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowImm)?;
596 if val_opt.is_none() {
597 return Err(CommandArgumentError::InvalidValueUsage.into());
598 }
599
600 if let &mut Some(Value::Receiving(_, _, ref mut recv_arg_type @ None)) = val_opt {
602 let Type::Reference(inner) = arg_type else {
603 return Err(CommandArgumentError::InvalidValueUsage.into());
604 };
605 *recv_arg_type = Some(*(*inner).clone());
606 }
607
608 Ok(V::try_from_value(val_opt.as_ref().unwrap().clone())?)
609 }
610
611 pub fn restore_arg<Mode: ExecutionMode>(
613 &mut self,
614 updates: &mut Mode::ArgumentUpdates,
615 arg: Arg,
616 value: Value,
617 ) -> Result<(), ExecutionError> {
618 Mode::add_argument_update(self, updates, arg.into(), &value)?;
619 let was_mut_opt = self.borrowed.remove(&arg);
620 assert_invariant!(
621 was_mut_opt.is_some() && was_mut_opt.unwrap(),
622 "Should never restore a non-mut borrowed value. \
623 The take+restore is an implementation detail of mutable references"
624 );
625 let Ok((_, value_opt)) = self.borrow_mut_impl(arg, None) else {
627 invariant_violation!("Should be able to borrow argument to restore it")
628 };
629
630 let old_value = value_opt.replace(value);
631 assert_invariant!(
632 old_value.is_none() || old_value.unwrap().is_copyable(),
633 "Should never restore a non-taken value, unless it is copyable. \
634 The take+restore is an implementation detail of mutable references"
635 );
636
637 Ok(())
638 }
639
640 pub fn transfer_object(
642 &mut self,
643 obj: ObjectValue,
644 addr: IotaAddress,
645 ) -> Result<(), ExecutionError> {
646 self.additional_transfers
647 .push((Owner::AddressOwner(addr), obj));
648 Ok(())
649 }
650
651 pub fn freeze_object(&mut self, obj: ObjectValue) -> Result<(), ExecutionError> {
653 self.additional_transfers.push((Owner::Immutable, obj));
654 Ok(())
655 }
656
657 pub fn new_package<'p>(
659 &self,
660 modules: &[CompiledModule],
661 dependencies: impl IntoIterator<Item = &'p MovePackage>,
662 ) -> Result<MovePackage, ExecutionError> {
663 MovePackage::new_initial(modules, self.protocol_config, dependencies)
664 }
665
666 pub fn upgrade_package<'p>(
669 &self,
670 storage_id: ObjectID,
671 previous_package: &MovePackage,
672 new_modules: &[CompiledModule],
673 dependencies: impl IntoIterator<Item = &'p MovePackage>,
674 ) -> Result<MovePackage, ExecutionError> {
675 previous_package.new_upgraded(
676 storage_id,
677 new_modules,
678 self.protocol_config,
679 dependencies,
680 )
681 }
682
683 pub fn write_package(&mut self, package: MovePackage) {
685 self.new_packages.push(package);
686 }
687
688 pub fn pop_package(&mut self) -> Option<MovePackage> {
694 self.new_packages.pop()
695 }
696
697 pub fn push_command_results(&mut self, results: Vec<Value>) -> Result<(), ExecutionError> {
700 assert_invariant!(
701 self.borrowed.values().all(|is_mut| !is_mut),
702 "all mut borrows should be restored"
703 );
704 self.borrowed = HashMap::new();
706 self.results
707 .push(results.into_iter().map(ResultValue::new).collect());
708 Ok(())
709 }
710
711 pub fn finish<Mode: ExecutionMode>(self) -> Result<ExecutionResults, ExecutionError> {
713 let Self {
714 protocol_config,
715 vm,
716 linkage_view,
717 mut native_extensions,
718 tx_context,
719 gas_charger,
720 additional_transfers,
721 new_packages,
722 gas,
723 inputs,
724 results,
725 user_events,
726 state_view,
727 ..
728 } = self;
729 let tx_digest = tx_context.digest();
730 let gas_id_opt = gas.object_metadata.as_ref().map(|info| info.id());
731 let mut loaded_runtime_objects = BTreeMap::new();
732 let mut additional_writes = BTreeMap::new();
733 let mut by_value_shared_objects = BTreeSet::new();
734 for input in inputs.into_iter().chain(std::iter::once(gas)) {
735 let InputValue {
736 object_metadata:
737 Some(InputObjectMetadata::InputObject {
738 is_mutable_input: true,
740 id,
741 version,
742 owner,
743 }),
744 inner: ResultValue { value, .. },
745 } = input
746 else {
747 continue;
748 };
749 loaded_runtime_objects.insert(
750 id,
751 LoadedRuntimeObject {
752 version,
753 is_modified: true,
754 },
755 );
756 if let Some(Value::Object(object_value)) = value {
757 add_additional_write(&mut additional_writes, owner, object_value)?;
758 } else if owner.is_shared() {
759 by_value_shared_objects.insert(id);
760 }
761 }
762 if !Mode::allow_arbitrary_values() {
765 for (i, command_result) in results.iter().enumerate() {
766 for (j, result_value) in command_result.iter().enumerate() {
767 let ResultValue {
768 last_usage_kind,
769 value,
770 } = result_value;
771 match value {
772 None => (),
773 Some(Value::Object(_)) => {
774 return Err(ExecutionErrorKind::UnusedValueWithoutDrop {
775 result_idx: i as u16,
776 secondary_idx: j as u16,
777 }
778 .into());
779 }
780 Some(Value::Raw(RawValueType::Any, _)) => (),
781 Some(Value::Raw(RawValueType::Loaded { abilities, .. }, _)) => {
782 if abilities.has_drop()
788 || (abilities.has_copy()
789 && matches!(last_usage_kind, Some(UsageKind::ByValue)))
790 {
791 } else {
792 let msg = if abilities.has_copy() {
793 "The value has copy, but not drop. \
794 Its last usage must be by-value so it can be taken."
795 } else {
796 "Unused value without drop"
797 };
798 return Err(ExecutionError::new_with_source(
799 ExecutionErrorKind::UnusedValueWithoutDrop {
800 result_idx: i as u16,
801 secondary_idx: j as u16,
802 },
803 msg,
804 ));
805 }
806 }
807 Some(Value::Receiving(_, _, _)) => (),
809 }
810 }
811 }
812 }
813 for (owner, object_value) in additional_transfers {
815 add_additional_write(&mut additional_writes, owner, object_value)?;
816 }
817 if let Some(gas_id) = gas_id_opt {
819 refund_max_gas_budget(&mut additional_writes, gas_charger, gas_id)?;
820 }
821
822 let object_runtime: ObjectRuntime = native_extensions
823 .remove()
824 .map_err(|e| convert_vm_error(e.finish(Location::Undefined), vm, &linkage_view))?;
825
826 let RuntimeResults {
827 writes,
828 user_events: remaining_events,
829 loaded_child_objects,
830 mut created_object_ids,
831 deleted_object_ids,
832 } = object_runtime.finish()?;
833 assert_invariant!(
834 remaining_events.is_empty(),
835 "Events should be taken after every Move call"
836 );
837
838 loaded_runtime_objects.extend(loaded_child_objects);
839
840 let mut written_objects = BTreeMap::new();
841 for package in new_packages {
842 let package_obj = Object::new_from_package(package, tx_digest);
843 let id = package_obj.id();
844 created_object_ids.insert(id);
845 written_objects.insert(id, package_obj);
846 }
847 for (id, additional_write) in additional_writes {
848 let AdditionalWrite {
849 recipient,
850 type_,
851 bytes,
852 } = additional_write;
853
854 let move_object = {
855 create_written_object(
856 vm,
857 &linkage_view,
858 protocol_config,
859 &loaded_runtime_objects,
860 id,
861 type_,
862 bytes,
863 )?
864 };
865 let object = Object::new_move(move_object, recipient, tx_digest);
866 written_objects.insert(id, object);
867 if let Some(loaded) = loaded_runtime_objects.get_mut(&id) {
868 loaded.is_modified = true;
869 }
870 }
871
872 for (id, (recipient, ty, value)) in writes {
873 let layout = vm
874 .get_runtime()
875 .type_to_type_layout(&ty)
876 .map_err(|e| convert_vm_error(e, vm, &linkage_view))?;
877 let Some(bytes) = value.simple_serialize(&layout) else {
878 invariant_violation!("Failed to deserialize already serialized Move value");
879 };
880 let move_object = {
881 create_written_object(
882 vm,
883 &linkage_view,
884 protocol_config,
885 &loaded_runtime_objects,
886 id,
887 ty,
888 bytes,
889 )?
890 };
891 let object = Object::new_move(move_object, recipient, tx_digest);
892 written_objects.insert(id, object);
893 }
894
895 for id in &by_value_shared_objects {
902 if let Some(obj) = written_objects.get(id) {
905 if !obj.is_shared() {
906 return Err(ExecutionError::new(
907 ExecutionErrorKind::SharedObjectOperationNotAllowed,
908 Some(
909 format!(
910 "Shared object operation on {id} not allowed: \
911 cannot be frozen, transferred, or wrapped"
912 )
913 .into(),
914 ),
915 ));
916 }
917 } else {
918 if !deleted_object_ids.contains(id) {
921 return Err(ExecutionError::new(
922 ExecutionErrorKind::SharedObjectOperationNotAllowed,
923 Some(
924 format!("Shared object operation on {id} not allowed: \
925 shared objects used by value must be re-shared if not deleted").into(),
926 ),
927 ));
928 }
929 }
930 }
931
932 let DenyListResult {
933 result,
934 num_non_gas_coin_owners,
935 } = state_view.check_coin_deny_list(&written_objects);
936 gas_charger.charge_coin_transfers(protocol_config, num_non_gas_coin_owners)?;
937 result?;
938
939 let user_events = user_events
940 .into_iter()
941 .map(|(module_id, tag, contents)| {
942 Event::new(
943 module_id.address(),
944 module_id.name(),
945 tx_context.sender(),
946 tag,
947 contents,
948 )
949 })
950 .collect();
951
952 Ok(ExecutionResults::V1(ExecutionResultsV1 {
953 written_objects,
954 modified_objects: loaded_runtime_objects
955 .into_iter()
956 .filter_map(|(id, loaded)| loaded.is_modified.then_some(id))
957 .collect(),
958 created_object_ids: created_object_ids.into_iter().collect(),
959 deleted_object_ids: deleted_object_ids.into_iter().collect(),
960 user_events,
961 }))
962 }
963
964 pub fn convert_vm_error(&self, error: VMError) -> ExecutionError {
966 crate::error::convert_vm_error(error, self.vm, &self.linkage_view)
967 }
968
969 pub fn convert_type_argument_error(&self, idx: usize, error: VMError) -> ExecutionError {
971 use iota_types::execution_status::TypeArgumentError;
972 use move_core_types::vm_status::StatusCode;
973 match error.major_status() {
974 StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
975 ExecutionErrorKind::TypeArityMismatch.into()
976 }
977 StatusCode::TYPE_RESOLUTION_FAILURE => ExecutionErrorKind::TypeArgumentError {
978 argument_idx: idx as TypeParameterIndex,
979 kind: TypeArgumentError::TypeNotFound,
980 }
981 .into(),
982 StatusCode::CONSTRAINT_NOT_SATISFIED => ExecutionErrorKind::TypeArgumentError {
983 argument_idx: idx as TypeParameterIndex,
984 kind: TypeArgumentError::ConstraintNotSatisfied,
985 }
986 .into(),
987 _ => self.convert_vm_error(error),
988 }
989 }
990
991 fn arg_is_borrowed(&self, arg: &Arg) -> bool {
994 self.borrowed.contains_key(arg)
995 }
996
997 fn arg_is_mut_borrowed(&self, arg: &Arg) -> bool {
1000 matches!(self.borrowed.get(arg), Some(true))
1001 }
1002
1003 fn borrow_mut(
1006 &mut self,
1007 arg: Arg,
1008 usage: UsageKind,
1009 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), EitherError> {
1010 self.borrow_mut_impl(arg, Some(usage))
1011 }
1012
1013 fn borrow_mut_impl(
1016 &mut self,
1017 arg: Arg,
1018 update_last_usage: Option<UsageKind>,
1019 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), EitherError> {
1020 match arg.0 {
1021 Arg_::V1(arg) => {
1022 assert_invariant!(
1023 !self.protocol_config.normalize_ptb_arguments(),
1024 "Should not be using v1 args with normalized args"
1025 );
1026 Ok(self.borrow_mut_impl_v1(arg, update_last_usage)?)
1027 }
1028 Arg_::V2(arg) => {
1029 assert_invariant!(
1030 self.protocol_config.normalize_ptb_arguments(),
1031 "Should be using only v2 args with normalized args"
1032 );
1033 Ok(self.borrow_mut_impl_v2(arg, update_last_usage)?)
1034 }
1035 }
1036 }
1037
1038 fn borrow_mut_impl_v1(
1040 &mut self,
1041 arg: Argument,
1042 update_last_usage: Option<UsageKind>,
1043 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), CommandArgumentError>
1044 {
1045 let (metadata, result_value) = match arg {
1046 Argument::GasCoin => (self.gas.object_metadata.as_ref(), &mut self.gas.inner),
1047 Argument::Input(i) => {
1048 let Some(input_value) = self.inputs.get_mut(i as usize) else {
1049 return Err(CommandArgumentError::IndexOutOfBounds { idx: i });
1050 };
1051 (input_value.object_metadata.as_ref(), &mut input_value.inner)
1052 }
1053 Argument::Result(i) => {
1054 let Some(command_result) = self.results.get_mut(i as usize) else {
1055 return Err(CommandArgumentError::IndexOutOfBounds { idx: i });
1056 };
1057 if command_result.len() != 1 {
1058 return Err(CommandArgumentError::InvalidResultArity { result_idx: i });
1059 }
1060 (None, &mut command_result[0])
1061 }
1062 Argument::NestedResult(i, j) => {
1063 let Some(command_result) = self.results.get_mut(i as usize) else {
1064 return Err(CommandArgumentError::IndexOutOfBounds { idx: i });
1065 };
1066 let Some(result_value) = command_result.get_mut(j as usize) else {
1067 return Err(CommandArgumentError::SecondaryIndexOutOfBounds {
1068 result_idx: i,
1069 secondary_idx: j,
1070 });
1071 };
1072 (None, result_value)
1073 }
1074 };
1075 if let Some(usage) = update_last_usage {
1076 result_value.last_usage_kind = Some(usage);
1077 }
1078 Ok((metadata, &mut result_value.value))
1079 }
1080
1081 fn borrow_mut_impl_v2(
1083 &mut self,
1084 arg: NormalizedArg,
1085 update_last_usage: Option<UsageKind>,
1086 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), ExecutionError> {
1087 let (metadata, result_value) = match arg {
1088 NormalizedArg::GasCoin => (self.gas.object_metadata.as_ref(), &mut self.gas.inner),
1089 NormalizedArg::Input(i) => {
1090 let input_value = self
1091 .inputs
1092 .get_mut(i as usize)
1093 .ok_or_else(|| make_invariant_violation!("bounds already checked"))?;
1094 (input_value.object_metadata.as_ref(), &mut input_value.inner)
1095 }
1096 NormalizedArg::Result(i, j) => {
1097 let result_value = self
1098 .results
1099 .get_mut(i as usize)
1100 .ok_or_else(|| make_invariant_violation!("bounds already checked"))?
1101 .get_mut(j as usize)
1102 .ok_or_else(|| make_invariant_violation!("bounds already checked"))?;
1103 (None, result_value)
1104 }
1105 };
1106 if let Some(usage) = update_last_usage {
1107 result_value.last_usage_kind = Some(usage);
1108 }
1109 Ok((metadata, &mut result_value.value))
1110 }
1111
1112 pub(crate) fn execute_function_bypass_visibility(
1117 &mut self,
1118 module: &ModuleId,
1119 function_name: &IdentStr,
1120 ty_args: Vec<Type>,
1121 args: Vec<impl Borrow<[u8]>>,
1122 tracer: &mut Option<MoveTraceBuilder>,
1123 ) -> VMResult<SerializedReturnValues> {
1124 let gas_status = self.gas_charger.move_gas_status_mut();
1125 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1126 self.vm.get_runtime().execute_function_bypass_visibility(
1127 module,
1128 function_name,
1129 ty_args,
1130 args,
1131 &mut data_store,
1132 &mut IotaGasMeter(gas_status),
1133 &mut self.native_extensions,
1134 tracer.as_mut(),
1135 )
1136 }
1137
1138 pub(crate) fn load_function(
1143 &mut self,
1144 module_id: &ModuleId,
1145 function_name: &IdentStr,
1146 type_arguments: &[Type],
1147 ) -> VMResult<LoadedFunctionInstantiation> {
1148 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1149 self.vm.get_runtime().load_function(
1150 module_id,
1151 function_name,
1152 type_arguments,
1153 &mut data_store,
1154 )
1155 }
1156
1157 pub(crate) fn make_object_value(
1162 &mut self,
1163 type_: MoveObjectType,
1164 used_in_non_entry_move_call: bool,
1165 contents: &[u8],
1166 ) -> Result<ObjectValue, ExecutionError> {
1167 make_object_value(
1168 self.vm,
1169 &mut self.linkage_view,
1170 &self.new_packages,
1171 type_,
1172 used_in_non_entry_move_call,
1173 contents,
1174 )
1175 }
1176
1177 pub fn publish_module_bundle(
1182 &mut self,
1183 modules: Vec<Vec<u8>>,
1184 sender: AccountAddress,
1185 ) -> VMResult<()> {
1186 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1189 self.vm.get_runtime().publish_module_bundle(
1190 modules,
1191 sender,
1192 &mut data_store,
1193 &mut IotaGasMeter(self.gas_charger.move_gas_status_mut()),
1194 )
1195 }
1196 }
1197
1198 impl TypeTagResolver for ExecutionContext<'_, '_, '_> {
1199 fn get_type_tag(&self, type_: &Type) -> Result<TypeTag, ExecutionError> {
1202 self.vm
1203 .get_runtime()
1204 .get_type_tag(type_)
1205 .map_err(|e| self.convert_vm_error(e))
1206 }
1207 }
1208
1209 fn package_for_linkage(
1213 linkage_view: &LinkageView,
1214 package_id: ObjectID,
1215 ) -> VMResult<PackageObject> {
1216 use move_binary_format::errors::PartialVMError;
1217 use move_core_types::vm_status::StatusCode;
1218
1219 match linkage_view.get_package_object(&package_id) {
1220 Ok(Some(package)) => Ok(package),
1221 Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1222 .with_message(format!("Cannot find link context {package_id} in store"))
1223 .finish(Location::Undefined)),
1224 Err(err) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1225 .with_message(format!(
1226 "Error loading link context {package_id} from store: {err}"
1227 ))
1228 .finish(Location::Undefined)),
1229 }
1230 }
1231
1232 pub fn load_type_from_struct(
1238 vm: &MoveVM,
1239 linkage_view: &mut LinkageView,
1240 new_packages: &[MovePackage],
1241 struct_tag: &StructTag,
1242 ) -> VMResult<Type> {
1243 fn verification_error<T>(code: StatusCode) -> VMResult<T> {
1244 Err(PartialVMError::new(code).finish(Location::Undefined))
1245 }
1246
1247 let StructTag {
1248 address,
1249 module,
1250 name,
1251 type_params,
1252 } = struct_tag;
1253
1254 let defining_id = ObjectID::from_address(*address);
1256 let package = package_for_linkage(linkage_view, defining_id)?;
1257
1258 let original_address = linkage_view
1261 .set_linkage(package.move_package())
1262 .map_err(|e| {
1263 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1264 .with_message(e.to_string())
1265 .finish(Location::Undefined)
1266 })?;
1267
1268 let runtime_id = ModuleId::new(original_address, module.clone());
1269 let data_store = IotaDataStore::new(linkage_view, new_packages);
1270 let res = vm.get_runtime().load_type(&runtime_id, name, &data_store);
1271 linkage_view.reset_linkage();
1272 let (idx, struct_type) = res?;
1273
1274 let type_param_constraints = struct_type.type_param_constraints();
1276 if type_param_constraints.len() != type_params.len() {
1277 return verification_error(StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH);
1278 }
1279
1280 if type_params.is_empty() {
1281 Ok(Type::Datatype(idx))
1282 } else {
1283 let loaded_type_params = type_params
1284 .iter()
1285 .map(|type_param| load_type(vm, linkage_view, new_packages, type_param))
1286 .collect::<VMResult<Vec<_>>>()?;
1287
1288 for (constraint, param) in type_param_constraints.zip(&loaded_type_params) {
1290 let abilities = vm.get_runtime().get_type_abilities(param)?;
1291 if !constraint.is_subset(abilities) {
1292 return verification_error(StatusCode::CONSTRAINT_NOT_SATISFIED);
1293 }
1294 }
1295
1296 Ok(Type::DatatypeInstantiation(Box::new((
1297 idx,
1298 loaded_type_params,
1299 ))))
1300 }
1301 }
1302
1303 pub fn load_type(
1307 vm: &MoveVM,
1308 linkage_view: &mut LinkageView,
1309 new_packages: &[MovePackage],
1310 type_tag: &TypeTag,
1311 ) -> VMResult<Type> {
1312 Ok(match type_tag {
1313 TypeTag::Bool => Type::Bool,
1314 TypeTag::U8 => Type::U8,
1315 TypeTag::U16 => Type::U16,
1316 TypeTag::U32 => Type::U32,
1317 TypeTag::U64 => Type::U64,
1318 TypeTag::U128 => Type::U128,
1319 TypeTag::U256 => Type::U256,
1320 TypeTag::Address => Type::Address,
1321 TypeTag::Signer => Type::Signer,
1322
1323 TypeTag::Vector(inner) => {
1324 Type::Vector(Box::new(load_type(vm, linkage_view, new_packages, inner)?))
1325 }
1326 TypeTag::Struct(struct_tag) => {
1327 return load_type_from_struct(vm, linkage_view, new_packages, struct_tag);
1328 }
1329 })
1330 }
1331
1332 pub(crate) fn make_object_value(
1339 vm: &MoveVM,
1340 linkage_view: &mut LinkageView,
1341 new_packages: &[MovePackage],
1342 type_: MoveObjectType,
1343 used_in_non_entry_move_call: bool,
1344 contents: &[u8],
1345 ) -> Result<ObjectValue, ExecutionError> {
1346 let contents = if type_.is_coin() {
1347 let Ok(coin) = Coin::from_bcs_bytes(contents) else {
1348 invariant_violation!("Could not deserialize a coin")
1349 };
1350 ObjectContents::Coin(coin)
1351 } else {
1352 ObjectContents::Raw(contents.to_vec())
1353 };
1354
1355 let tag: StructTag = type_.into();
1356 let type_ = load_type_from_struct(vm, linkage_view, new_packages, &tag)
1357 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1358 let abilities = vm
1359 .get_runtime()
1360 .get_type_abilities(&type_)
1361 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1362 let has_public_transfer = abilities.has_store();
1363 Ok(ObjectValue {
1364 type_,
1365 has_public_transfer,
1366 used_in_non_entry_move_call,
1367 contents,
1368 })
1369 }
1370
1371 impl Arg {
1372 fn is_gas_coin(&self) -> bool {
1373 match self {
1375 Arg(Arg_::V1(a)) => matches!(a, Argument::GasCoin),
1376 Arg(Arg_::V2(n)) => matches!(n, NormalizedArg::GasCoin),
1377 }
1378 }
1379 }
1380
1381 impl From<Arg> for Argument {
1382 fn from(arg: Arg) -> Self {
1383 match arg.0 {
1384 Arg_::V1(a) => a,
1385 Arg_::V2(normalized) => match normalized {
1386 NormalizedArg::GasCoin => Argument::GasCoin,
1387 NormalizedArg::Input(i) => Argument::Input(i),
1388 NormalizedArg::Result(i, j) => Argument::NestedResult(i, j),
1389 },
1390 }
1391 }
1392 }
1393
1394 pub(crate) fn value_from_object(
1399 vm: &MoveVM,
1400 linkage_view: &mut LinkageView,
1401 new_packages: &[MovePackage],
1402 object: &Object,
1403 ) -> Result<ObjectValue, ExecutionError> {
1404 let ObjectInner {
1405 data: Data::Move(object),
1406 ..
1407 } = object.as_inner()
1408 else {
1409 invariant_violation!("Expected a Move object");
1410 };
1411
1412 let used_in_non_entry_move_call = false;
1413 make_object_value(
1414 vm,
1415 linkage_view,
1416 new_packages,
1417 object.type_().clone(),
1418 used_in_non_entry_move_call,
1419 object.contents(),
1420 )
1421 }
1422
1423 fn load_object(
1425 vm: &MoveVM,
1426 state_view: &dyn ExecutionState,
1427 linkage_view: &mut LinkageView,
1428 new_packages: &[MovePackage],
1429 input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1430 override_as_immutable: bool,
1431 id: ObjectID,
1432 ) -> Result<InputValue, ExecutionError> {
1433 let Some(obj) = state_view.read_object(&id) else {
1434 invariant_violation!("Object {} does not exist yet", id);
1436 };
1437 assert_invariant!(
1439 !override_as_immutable || matches!(obj.owner, Owner::Shared { .. }),
1440 "override_as_immutable should only be set for shared objects"
1441 );
1442 let is_mutable_input = match obj.owner {
1443 Owner::AddressOwner(_) => true,
1444 Owner::Shared { .. } => !override_as_immutable,
1445 Owner::Immutable => false,
1446 Owner::ObjectOwner(_) => {
1447 invariant_violation!("ObjectOwner objects cannot be input")
1449 }
1450 };
1451 let owner = obj.owner;
1452 let version = obj.version();
1453 let object_metadata = InputObjectMetadata::InputObject {
1454 id,
1455 is_mutable_input,
1456 owner,
1457 version,
1458 };
1459 let obj_value = value_from_object(vm, linkage_view, new_packages, obj)?;
1460 let contained_uids = {
1461 let fully_annotated_layout = vm
1462 .get_runtime()
1463 .type_to_fully_annotated_layout(&obj_value.type_)
1464 .map_err(|e| convert_vm_error(e, vm, linkage_view))?;
1465 let mut bytes = vec![];
1466 obj_value.write_bcs_bytes(&mut bytes, None)?;
1467 match get_all_uids(&fully_annotated_layout, &bytes) {
1468 Err(e) => {
1469 invariant_violation!("Unable to retrieve UIDs for object. Got error: {e}")
1470 }
1471 Ok(uids) => uids,
1472 }
1473 };
1474 let runtime_input = object_runtime::InputObject {
1475 contained_uids,
1476 owner,
1477 version,
1478 };
1479 let prev = input_object_map.insert(id, runtime_input);
1480 assert_invariant!(prev.is_none(), "Duplicate input object {}", id);
1482 Ok(InputValue::new_object(object_metadata, obj_value))
1483 }
1484
1485 fn load_call_arg(
1487 vm: &MoveVM,
1488 state_view: &dyn ExecutionState,
1489 linkage_view: &mut LinkageView,
1490 new_packages: &[MovePackage],
1491 input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1492 call_arg: CallArg,
1493 ) -> Result<InputValue, ExecutionError> {
1494 Ok(match call_arg {
1495 CallArg::Pure(bytes) => InputValue::new_raw(RawValueType::Any, bytes),
1496 CallArg::Object(obj_arg) => load_object_arg(
1497 vm,
1498 state_view,
1499 linkage_view,
1500 new_packages,
1501 input_object_map,
1502 obj_arg,
1503 )?,
1504 })
1505 }
1506
1507 fn load_object_arg(
1510 vm: &MoveVM,
1511 state_view: &dyn ExecutionState,
1512 linkage_view: &mut LinkageView,
1513 new_packages: &[MovePackage],
1514 input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1515 obj_arg: ObjectArg,
1516 ) -> Result<InputValue, ExecutionError> {
1517 match obj_arg {
1518 ObjectArg::ImmOrOwnedObject((id, _, _)) => load_object(
1519 vm,
1520 state_view,
1521 linkage_view,
1522 new_packages,
1523 input_object_map,
1524 false,
1526 id,
1527 ),
1528 ObjectArg::SharedObject { id, mutable, .. } => load_object(
1529 vm,
1530 state_view,
1531 linkage_view,
1532 new_packages,
1533 input_object_map,
1534 !mutable,
1536 id,
1537 ),
1538 ObjectArg::Receiving((id, version, _)) => {
1539 Ok(InputValue::new_receiving_object(id, version))
1540 }
1541 }
1542 }
1543
1544 fn add_additional_write(
1546 additional_writes: &mut BTreeMap<ObjectID, AdditionalWrite>,
1547 owner: Owner,
1548 object_value: ObjectValue,
1549 ) -> Result<(), ExecutionError> {
1550 let ObjectValue {
1551 type_, contents, ..
1552 } = object_value;
1553 let bytes = match contents {
1554 ObjectContents::Coin(coin) => coin.to_bcs_bytes(),
1555 ObjectContents::Raw(bytes) => bytes,
1556 };
1557 let object_id = MoveObject::id_opt(&bytes).map_err(|e| {
1558 ExecutionError::invariant_violation(format!("No id for Raw object bytes. {e}"))
1559 })?;
1560 let additional_write = AdditionalWrite {
1561 recipient: owner,
1562 type_,
1563 bytes,
1564 };
1565 additional_writes.insert(object_id, additional_write);
1566 Ok(())
1567 }
1568
1569 fn refund_max_gas_budget(
1573 additional_writes: &mut BTreeMap<ObjectID, AdditionalWrite>,
1574 gas_charger: &mut GasCharger,
1575 gas_id: ObjectID,
1576 ) -> Result<(), ExecutionError> {
1577 let Some(AdditionalWrite { bytes, .. }) = additional_writes.get_mut(&gas_id) else {
1578 invariant_violation!("Gas object cannot be wrapped or destroyed")
1579 };
1580 let Ok(mut coin) = Coin::from_bcs_bytes(bytes) else {
1581 invariant_violation!("Gas object must be a coin")
1582 };
1583 let Some(new_balance) = coin.balance.value().checked_add(gas_charger.gas_budget()) else {
1584 return Err(ExecutionError::new_with_source(
1585 ExecutionErrorKind::CoinBalanceOverflow,
1586 "Gas coin too large after returning the max gas budget",
1587 ));
1588 };
1589 coin.balance = Balance::new(new_balance);
1590 *bytes = coin.to_bcs_bytes();
1591 Ok(())
1592 }
1593
1594 fn create_written_object(
1596 vm: &MoveVM,
1597 linkage_view: &LinkageView,
1598 protocol_config: &ProtocolConfig,
1599 objects_modified_at: &BTreeMap<ObjectID, LoadedRuntimeObject>,
1600 id: ObjectID,
1601 type_: Type,
1602 contents: Vec<u8>,
1603 ) -> Result<MoveObject, ExecutionError> {
1604 debug_assert_eq!(
1605 id,
1606 MoveObject::id_opt(&contents).expect("object contents should start with an id")
1607 );
1608 let old_obj_ver = objects_modified_at
1609 .get(&id)
1610 .map(|obj: &LoadedRuntimeObject| obj.version);
1611
1612 let type_tag = vm
1613 .get_runtime()
1614 .get_type_tag(&type_)
1615 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1616
1617 let struct_tag = match type_tag {
1618 TypeTag::Struct(inner) => *inner,
1619 _ => invariant_violation!("Non struct type for object"),
1620 };
1621 MoveObject::new_from_execution(
1622 struct_tag.into(),
1623 old_obj_ver.unwrap_or_default(),
1624 contents,
1625 protocol_config,
1626 )
1627 }
1628
1629 pub(crate) struct IotaDataStore<'state, 'a> {
1637 linkage_view: &'a LinkageView<'state>,
1638 new_packages: &'a [MovePackage],
1639 }
1640
1641 impl<'state, 'a> IotaDataStore<'state, 'a> {
1642 pub(crate) fn new(
1643 linkage_view: &'a LinkageView<'state>,
1644 new_packages: &'a [MovePackage],
1645 ) -> Self {
1646 Self {
1647 linkage_view,
1648 new_packages,
1649 }
1650 }
1651
1652 fn get_module(&self, module_id: &ModuleId) -> Option<&Vec<u8>> {
1653 for package in self.new_packages {
1654 let module = package.get_module(module_id);
1655 if module.is_some() {
1656 return module;
1657 }
1658 }
1659 None
1660 }
1661 }
1662
1663 impl DataStore for IotaDataStore<'_, '_> {
1667 fn link_context(&self) -> AccountAddress {
1668 self.linkage_view.link_context()
1669 }
1670
1671 fn relocate(&self, module_id: &ModuleId) -> PartialVMResult<ModuleId> {
1672 self.linkage_view.relocate(module_id).map_err(|err| {
1673 PartialVMError::new(StatusCode::LINKER_ERROR)
1674 .with_message(format!("Error relocating {module_id}: {err:?}"))
1675 })
1676 }
1677
1678 fn defining_module(
1679 &self,
1680 runtime_id: &ModuleId,
1681 struct_: &IdentStr,
1682 ) -> PartialVMResult<ModuleId> {
1683 self.linkage_view
1684 .defining_module(runtime_id, struct_)
1685 .map_err(|err| {
1686 PartialVMError::new(StatusCode::LINKER_ERROR).with_message(format!(
1687 "Error finding defining module for {runtime_id}::{struct_}: {err:?}"
1688 ))
1689 })
1690 }
1691
1692 fn load_module(&self, module_id: &ModuleId) -> VMResult<Vec<u8>> {
1693 if let Some(bytes) = self.get_module(module_id) {
1694 return Ok(bytes.clone());
1695 }
1696 match self.linkage_view.get_module(module_id) {
1697 Ok(Some(bytes)) => Ok(bytes),
1698 Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1699 .with_message(format!("Cannot find {module_id:?} in data cache"))
1700 .finish(Location::Undefined)),
1701 Err(err) => {
1702 let msg = format!("Unexpected storage error: {err:?}");
1703 Err(
1704 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1705 .with_message(msg)
1706 .finish(Location::Undefined),
1707 )
1708 }
1709 }
1710 }
1711
1712 fn publish_module(&mut self, _module_id: &ModuleId, _blob: Vec<u8>) -> VMResult<()> {
1713 Ok(())
1716 }
1717 }
1718
1719 enum EitherError {
1720 CommandArgument(CommandArgumentError),
1721 Execution(ExecutionError),
1722 }
1723
1724 impl From<ExecutionError> for EitherError {
1725 fn from(e: ExecutionError) -> Self {
1726 EitherError::Execution(e)
1727 }
1728 }
1729
1730 impl From<CommandArgumentError> for EitherError {
1731 fn from(e: CommandArgumentError) -> Self {
1732 EitherError::CommandArgument(e)
1733 }
1734 }
1735
1736 impl EitherError {
1737 fn into_execution_error(self, command_index: usize) -> ExecutionError {
1738 match self {
1739 EitherError::CommandArgument(e) => command_argument_error(e, command_index),
1740 EitherError::Execution(e) => e,
1741 }
1742 }
1743 }
1744}