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_types::{
22 balance::Balance,
23 base_types::{Identifier, IotaAddress, ObjectID, StructTag, TxContext, TypeTag},
24 coin::Coin,
25 error::{ExecutionError, ExecutionErrorKind, command_argument_error},
26 event::Event,
27 execution::{ExecutionResults, ExecutionResultsV1},
28 execution_status::CommandArgumentError,
29 iota_sdk_types_conversions::{struct_tag_core_to_sdk, type_tag_core_to_sdk},
30 metrics::LimitsMetrics,
31 move_package::{MovePackage, MovePackageExt, derive_package_metadata_id},
32 object::{Data, MoveObject, MoveObjectExt, Object, ObjectInner, Owner},
33 storage::{BackingPackageStore, DenyListResult, PackageObject},
34 transaction::{Argument, CallArg, SharedObjectRef},
35 };
36 use move_binary_format::{
37 CompiledModule,
38 errors::{Location, PartialVMError, PartialVMResult, VMError, VMResult},
39 file_format::{CodeOffset, FunctionDefinitionIndex, TypeParameterIndex},
40 };
41 use move_core_types::{
42 account_address::AccountAddress, identifier::IdentStr, language_storage::ModuleId,
43 resolver::ModuleResolver, 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: Rc<RefCell<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: Rc<RefCell<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.clone(),
217 state_view.read_auth_context(),
218 );
219
220 #[skip_checked_arithmetic]
222 move_vm_profiler::tracing_feature_enabled! {
223 use move_vm_profiler::GasProfiler;
224 use move_vm_types::gas::GasMeter;
225
226 let ref_context: &RefCell<TxContext> = tx_context.borrow();
227 let tx_digest = ref_context.borrow().digest();
228 let remaining_gas: u64 =
229 move_vm_types::gas::GasMeter::remaining_gas(&IotaGasMeter(gas_charger.move_gas_status_mut()))
230 .into();
231 IotaGasMeter(gas_charger.move_gas_status_mut())
232 .set_profiler(GasProfiler::init(
233 &vm.config().profiler_config,
234 format!("{tx_digest}"),
235 remaining_gas,
236 ));
237 }
238
239 Ok(Self {
240 protocol_config,
241 metrics,
242 vm,
243 linkage_view,
244 native_extensions,
245 state_view,
246 tx_context,
247 gas_charger,
248 gas,
249 inputs,
250 results: vec![],
251 additional_transfers: vec![],
252 new_packages: vec![],
253 user_events: vec![],
254 borrowed: HashMap::new(),
255 })
256 }
257
258 pub fn object_runtime(&self) -> Result<&ObjectRuntime<'_>, ExecutionError> {
259 self.native_extensions
260 .get::<ObjectRuntime>()
261 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))
262 }
263
264 pub fn fresh_id(&mut self) -> Result<ObjectID, ExecutionError> {
266 let object_id = self.tx_context.borrow_mut().fresh_id();
267 self.native_extensions
268 .get_mut()
269 .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.new_id(object_id))
270 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
271 Ok(object_id)
272 }
273
274 pub(crate) fn package_derived_metadata_id(
276 &mut self,
277 package_storage_id: ObjectID,
278 ) -> Result<ObjectID, ExecutionError> {
279 let object_id = derive_package_metadata_id(package_storage_id);
280
281 self.native_extensions
282 .get_mut()
283 .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.new_id(object_id))
284 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
285 Ok(object_id)
286 }
287
288 pub fn delete_id(&mut self, object_id: ObjectID) -> Result<(), ExecutionError> {
290 self.native_extensions
291 .get_mut()
292 .and_then(|object_runtime: &mut ObjectRuntime| object_runtime.delete_id(object_id))
293 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))
294 }
295
296 pub fn set_link_context(
300 &mut self,
301 package_id: ObjectID,
302 ) -> Result<AccountAddress, ExecutionError> {
303 if self.linkage_view.has_linkage(package_id) {
304 return Ok(self
306 .linkage_view
307 .original_package_id()
308 .unwrap_or(AccountAddress::new(package_id.into_bytes())));
309 }
310
311 let package = package_for_linkage(&self.linkage_view, package_id)
312 .map_err(|e| self.convert_vm_error(e))?;
313
314 self.linkage_view.set_linkage(package.move_package())
315 }
316
317 pub fn load_type(&mut self, type_tag: &TypeTag) -> VMResult<Type> {
319 load_type(
320 self.vm,
321 &mut self.linkage_view,
322 &self.new_packages,
323 type_tag,
324 )
325 }
326
327 pub fn load_type_from_struct(&mut self, struct_tag: &StructTag) -> VMResult<Type> {
329 load_type_from_struct(
330 self.vm,
331 &mut self.linkage_view,
332 &self.new_packages,
333 struct_tag,
334 )
335 }
336
337 pub fn take_user_events(
340 &mut self,
341 module_id: &ModuleId,
342 function: FunctionDefinitionIndex,
343 last_offset: CodeOffset,
344 ) -> Result<(), ExecutionError> {
345 let events = self
346 .native_extensions
347 .get_mut()
348 .map(|object_runtime: &mut ObjectRuntime| object_runtime.take_user_events())
349 .map_err(|e| self.convert_vm_error(e.finish(Location::Undefined)))?;
350 let num_events = self.user_events.len() + events.len();
351 let max_events = self.protocol_config.max_num_event_emit();
352 if num_events as u64 > max_events {
353 let err = max_event_error(max_events)
354 .at_code_offset(function, last_offset)
355 .finish(Location::Module(module_id.clone()));
356 return Err(self.convert_vm_error(err));
357 }
358 let new_events = events
359 .into_iter()
360 .map(|(ty, tag, value)| {
361 let layout = self
362 .vm
363 .get_runtime()
364 .type_to_type_layout(&ty)
365 .map_err(|e| self.convert_vm_error(e))?;
366 let Some(bytes) = value.simple_serialize(&layout) else {
367 invariant_violation!("Failed to deserialize already serialized Move value");
368 };
369 Ok((module_id.clone(), struct_tag_core_to_sdk(&tag), bytes))
370 })
371 .collect::<Result<Vec<_>, ExecutionError>>()?;
372 self.user_events.extend(new_events);
373 Ok(())
374 }
375
376 pub fn splat_args<Items: IntoIterator<Item = Argument>>(
382 &self,
383 start_idx: usize,
384 args: Items,
385 ) -> Result<Vec<Arg>, ExecutionError>
386 where
387 Items::IntoIter: ExactSizeIterator,
388 {
389 if !self.protocol_config.normalize_ptb_arguments() {
390 Ok(args.into_iter().map(|arg| Arg(Arg_::V1(arg))).collect())
391 } else {
392 let args = args.into_iter();
393 let _args_len = args.len();
394 let mut res = vec![];
395 for (arg_idx, arg) in args.enumerate() {
396 self.splat_arg(&mut res, arg)
397 .map_err(|e| e.into_execution_error(start_idx + arg_idx))?;
398 }
399 debug_assert_eq!(res.len(), _args_len);
400 Ok(res)
401 }
402 }
403
404 fn splat_arg(&self, res: &mut Vec<Arg>, arg: Argument) -> Result<(), EitherError> {
405 match arg {
406 Argument::Gas => res.push(Arg(Arg_::V2(NormalizedArg::GasCoin))),
407 Argument::Input(i) => {
408 if i as usize >= self.inputs.len() {
409 return Err(CommandArgumentError::IndexOutOfBounds { index: i }.into());
410 }
411 res.push(Arg(Arg_::V2(NormalizedArg::Input(i))))
412 }
413 Argument::NestedResult(i, j) => {
414 let Some(command_result) = self.results.get(i as usize) else {
415 return Err(CommandArgumentError::IndexOutOfBounds { index: i }.into());
416 };
417 if j as usize >= command_result.len() {
418 return Err(CommandArgumentError::SecondaryIndexOutOfBounds {
419 result: i,
420 subresult: j,
421 }
422 .into());
423 };
424 res.push(Arg(Arg_::V2(NormalizedArg::Result(i, j))))
425 }
426 Argument::Result(i) => {
427 let Some(result) = self.results.get(i as usize) else {
428 return Err(CommandArgumentError::IndexOutOfBounds { index: i }.into());
429 };
430 let Ok(len): Result<u16, _> = result.len().try_into() else {
431 invariant_violation!("Result of length greater than u16::MAX");
432 };
433 if len != 1 {
434 return Err(CommandArgumentError::InvalidResultArity { result: i }.into());
436 }
437 res.extend((0..len).map(|j| Arg(Arg_::V2(NormalizedArg::Result(i, j)))))
438 }
439 _ => {
440 unimplemented!("a new Argument enum variant was added and needs to be handled")
441 }
442 }
443 Ok(())
444 }
445
446 pub fn one_arg(
447 &self,
448 command_arg_idx: usize,
449 arg: Argument,
450 ) -> Result<Arg, ExecutionError> {
451 let args = self.splat_args(command_arg_idx, vec![arg])?;
452 let Ok([arg]): Result<[Arg; 1], _> = args.try_into() else {
453 return Err(command_argument_error(
454 CommandArgumentError::InvalidArgumentArity,
455 command_arg_idx,
456 ));
457 };
458 Ok(arg)
459 }
460
461 pub fn by_value_arg<V: TryFromValue>(
467 &mut self,
468 command_kind: CommandKind,
469 arg_idx: usize,
470 arg: Arg,
471 ) -> Result<V, ExecutionError> {
472 self.by_value_arg_(command_kind, arg)
473 .map_err(|e| e.into_execution_error(arg_idx))
474 }
475 fn by_value_arg_<V: TryFromValue>(
476 &mut self,
477 command_kind: CommandKind,
478 arg: Arg,
479 ) -> Result<V, EitherError> {
480 let is_borrowed = self.arg_is_borrowed(&arg);
481 let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::ByValue)?;
482 let is_copyable = if let Some(val) = val_opt {
483 val.is_copyable()
484 } else {
485 return Err(CommandArgumentError::InvalidValueUsage.into());
486 };
487 if !is_copyable && is_borrowed {
493 return Err(CommandArgumentError::InvalidValueUsage.into());
494 }
495 if arg.is_gas_coin() && !matches!(command_kind, CommandKind::TransferObjects) {
497 return Err(CommandArgumentError::InvalidGasCoinUsage.into());
498 }
499 if matches!(
501 input_metadata_opt,
502 Some(InputObjectMetadata::InputObject {
503 owner: Owner::Immutable,
504 ..
505 })
506 ) {
507 return Err(CommandArgumentError::InvalidObjectByValue.into());
508 }
509
510 if matches!(
512 input_metadata_opt,
513 Some(InputObjectMetadata::InputObject {
514 is_mutable_input: false,
515 ..
516 })
517 ) {
518 return Err(CommandArgumentError::InvalidObjectByValue.into());
519 }
520
521 let val = if is_copyable {
522 val_opt.as_ref().unwrap().clone()
523 } else {
524 val_opt.take().unwrap()
525 };
526 Ok(V::try_from_value(val)?)
527 }
528
529 pub fn borrow_arg_mut<V: TryFromValue>(
536 &mut self,
537 arg_idx: usize,
538 arg: Arg,
539 ) -> Result<V, ExecutionError> {
540 self.borrow_arg_mut_(arg)
541 .map_err(|e| e.into_execution_error(arg_idx))
542 }
543 fn borrow_arg_mut_<V: TryFromValue>(&mut self, arg: Arg) -> Result<V, EitherError> {
544 if self.arg_is_borrowed(&arg) {
546 return Err(CommandArgumentError::InvalidValueUsage.into());
547 }
548 self.borrowed.insert(arg, true);
549 let (input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowMut)?;
550 let is_copyable = if let Some(val) = val_opt {
551 val.is_copyable()
552 } else {
553 return Err(CommandArgumentError::InvalidValueUsage.into());
555 };
556 if let Some(InputObjectMetadata::InputObject {
557 is_mutable_input: false,
558 ..
559 }) = input_metadata_opt
560 {
561 return Err(CommandArgumentError::InvalidObjectByMutRef.into());
562 }
563 let val = if is_copyable {
566 val_opt.as_ref().unwrap().clone()
567 } else {
568 val_opt.take().unwrap()
569 };
570 Ok(V::try_from_value(val)?)
571 }
572
573 pub fn borrow_arg<V: TryFromValue>(
578 &mut self,
579 arg_idx: usize,
580 arg: Arg,
581 type_: &Type,
582 ) -> Result<V, ExecutionError> {
583 self.borrow_arg_(arg, type_)
584 .map_err(|e| e.into_execution_error(arg_idx))
585 }
586 fn borrow_arg_<V: TryFromValue>(
587 &mut self,
588 arg: Arg,
589 arg_type: &Type,
590 ) -> Result<V, EitherError> {
591 if self.arg_is_mut_borrowed(&arg) {
595 return Err(CommandArgumentError::InvalidValueUsage.into());
596 }
597 self.borrowed.insert(arg, false);
598 let (_input_metadata_opt, val_opt) = self.borrow_mut(arg, UsageKind::BorrowImm)?;
599 if val_opt.is_none() {
600 return Err(CommandArgumentError::InvalidValueUsage.into());
601 }
602
603 if let &mut Some(Value::Receiving(_, _, ref mut recv_arg_type @ None)) = val_opt {
605 let Type::Reference(inner) = arg_type else {
606 return Err(CommandArgumentError::InvalidValueUsage.into());
607 };
608 *recv_arg_type = Some(*(*inner).clone());
609 }
610
611 Ok(V::try_from_value(val_opt.as_ref().unwrap().clone())?)
612 }
613
614 pub fn restore_arg<Mode: ExecutionMode>(
616 &mut self,
617 updates: &mut Mode::ArgumentUpdates,
618 arg: Arg,
619 value: Value,
620 ) -> Result<(), ExecutionError> {
621 Mode::add_argument_update(self, updates, arg.into(), &value)?;
622 let was_mut_opt = self.borrowed.remove(&arg);
623 assert_invariant!(
624 was_mut_opt.is_some() && was_mut_opt.unwrap(),
625 "Should never restore a non-mut borrowed value. \
626 The take+restore is an implementation detail of mutable references"
627 );
628 let Ok((_, value_opt)) = self.borrow_mut_impl(arg, None) else {
630 invariant_violation!("Should be able to borrow argument to restore it")
631 };
632
633 let old_value = value_opt.replace(value);
634 assert_invariant!(
635 old_value.is_none() || old_value.unwrap().is_copyable(),
636 "Should never restore a non-taken value, unless it is copyable. \
637 The take+restore is an implementation detail of mutable references"
638 );
639
640 Ok(())
641 }
642
643 pub fn transfer_object(
645 &mut self,
646 obj: ObjectValue,
647 addr: IotaAddress,
648 ) -> Result<(), ExecutionError> {
649 self.additional_transfers.push((Owner::Address(addr), obj));
650 Ok(())
651 }
652
653 pub fn freeze_object(&mut self, obj: ObjectValue) -> Result<(), ExecutionError> {
655 self.additional_transfers.push((Owner::Immutable, obj));
656 Ok(())
657 }
658
659 pub fn new_package<'p>(
661 &self,
662 modules: &[CompiledModule],
663 dependencies: impl IntoIterator<Item = &'p MovePackage>,
664 ) -> Result<MovePackage, ExecutionError> {
665 MovePackage::new_initial(modules, self.protocol_config, dependencies)
666 }
667
668 pub fn upgrade_package<'p>(
671 &self,
672 storage_id: ObjectID,
673 previous_package: &MovePackage,
674 new_modules: &[CompiledModule],
675 dependencies: impl IntoIterator<Item = &'p MovePackage>,
676 ) -> Result<MovePackage, ExecutionError> {
677 previous_package.new_upgraded(
678 storage_id,
679 new_modules,
680 self.protocol_config,
681 dependencies,
682 )
683 }
684
685 pub fn write_package(&mut self, package: MovePackage) {
687 self.new_packages.push(package);
688 }
689
690 pub fn pop_package(&mut self) -> Option<MovePackage> {
696 self.new_packages.pop()
697 }
698
699 pub fn push_command_results(&mut self, results: Vec<Value>) -> Result<(), ExecutionError> {
702 assert_invariant!(
703 self.borrowed.values().all(|is_mut| !is_mut),
704 "all mut borrows should be restored"
705 );
706 self.borrowed = HashMap::new();
708 self.results
709 .push(results.into_iter().map(ResultValue::new).collect());
710 Ok(())
711 }
712
713 pub fn finish<Mode: ExecutionMode>(self) -> Result<ExecutionResults, ExecutionError> {
715 let Self {
716 protocol_config,
717 vm,
718 linkage_view,
719 mut native_extensions,
720 tx_context,
721 gas_charger,
722 additional_transfers,
723 new_packages,
724 gas,
725 inputs,
726 results,
727 user_events,
728 state_view,
729 ..
730 } = self;
731 let ref_context: &RefCell<TxContext> = tx_context.borrow();
732 let tx_digest = ref_context.borrow().digest();
733
734 let gas_id_opt = gas.object_metadata.as_ref().map(|info| info.id());
735 let mut loaded_runtime_objects = BTreeMap::new();
736 let mut additional_writes = BTreeMap::new();
737 let mut by_value_shared_objects = BTreeSet::new();
738 for input in inputs.into_iter().chain(std::iter::once(gas)) {
739 let InputValue {
740 object_metadata:
741 Some(InputObjectMetadata::InputObject {
742 is_mutable_input: true,
744 id,
745 version,
746 owner,
747 }),
748 inner: ResultValue { value, .. },
749 } = input
750 else {
751 continue;
752 };
753 loaded_runtime_objects.insert(
754 id,
755 LoadedRuntimeObject {
756 version,
757 is_modified: true,
758 },
759 );
760 if let Some(Value::Object(object_value)) = value {
761 add_additional_write(&mut additional_writes, owner, object_value)?;
762 } else if owner.is_shared() {
763 by_value_shared_objects.insert(id);
764 }
765 }
766 if !Mode::allow_arbitrary_values() {
769 for (i, command_result) in results.iter().enumerate() {
770 for (j, result_value) in command_result.iter().enumerate() {
771 let ResultValue {
772 last_usage_kind,
773 value,
774 } = result_value;
775 match value {
776 None => (),
777 Some(Value::Object(_)) => {
778 return Err(ExecutionErrorKind::UnusedValueWithoutDrop {
779 result: i as u16,
780 subresult: j as u16,
781 }
782 .into());
783 }
784 Some(Value::Raw(RawValueType::Any, _)) => (),
785 Some(Value::Raw(RawValueType::Loaded { abilities, .. }, _)) => {
786 if abilities.has_drop()
792 || (abilities.has_copy()
793 && matches!(last_usage_kind, Some(UsageKind::ByValue)))
794 {
795 } else {
796 let msg = if abilities.has_copy() {
797 "The value has copy, but not drop. \
798 Its last usage must be by-value so it can be taken."
799 } else {
800 "Unused value without drop"
801 };
802 return Err(ExecutionError::new_with_source(
803 ExecutionErrorKind::UnusedValueWithoutDrop {
804 result: i as u16,
805 subresult: j as u16,
806 },
807 msg,
808 ));
809 }
810 }
811 Some(Value::Receiving(_, _, _)) => (),
813 }
814 }
815 }
816 }
817 for (owner, object_value) in additional_transfers {
819 add_additional_write(&mut additional_writes, owner, object_value)?;
820 }
821 if let Some(gas_id) = gas_id_opt {
823 refund_max_gas_budget(&mut additional_writes, gas_charger, gas_id)?;
824 }
825
826 let object_runtime: ObjectRuntime = native_extensions
827 .remove()
828 .map_err(|e| convert_vm_error(e.finish(Location::Undefined), vm, &linkage_view))?;
829
830 let RuntimeResults {
831 writes,
832 user_events: remaining_events,
833 loaded_child_objects,
834 mut created_object_ids,
835 deleted_object_ids,
836 } = object_runtime.finish()?;
837 assert_invariant!(
838 remaining_events.is_empty(),
839 "Events should be taken after every Move call"
840 );
841
842 loaded_runtime_objects.extend(loaded_child_objects);
843
844 let mut written_objects = BTreeMap::new();
845 for package in new_packages {
846 let package_obj = Object::new_from_package(package, tx_digest);
847 let id = package_obj.id();
848 created_object_ids.insert(id);
849 written_objects.insert(id, package_obj);
850 }
851 for (id, additional_write) in additional_writes {
852 let AdditionalWrite {
853 recipient,
854 type_,
855 bytes,
856 } = additional_write;
857
858 let move_object = {
859 create_written_object(
860 vm,
861 &linkage_view,
862 protocol_config,
863 &loaded_runtime_objects,
864 id,
865 type_,
866 bytes,
867 )?
868 };
869 let object = Object::new_move(move_object, recipient, tx_digest);
870 written_objects.insert(id, object);
871 if let Some(loaded) = loaded_runtime_objects.get_mut(&id) {
872 loaded.is_modified = true;
873 }
874 }
875
876 for (id, (recipient, ty, value)) in writes {
877 let layout = vm
878 .get_runtime()
879 .type_to_type_layout(&ty)
880 .map_err(|e| convert_vm_error(e, vm, &linkage_view))?;
881 let Some(bytes) = value.simple_serialize(&layout) else {
882 invariant_violation!("Failed to deserialize already serialized Move value");
883 };
884 let move_object = {
885 create_written_object(
886 vm,
887 &linkage_view,
888 protocol_config,
889 &loaded_runtime_objects,
890 id,
891 ty,
892 bytes,
893 )?
894 };
895 let object = Object::new_move(move_object, recipient, tx_digest);
896 written_objects.insert(id, object);
897 }
898
899 for id in &by_value_shared_objects {
906 if let Some(obj) = written_objects.get(id) {
909 if !obj.is_shared() {
910 return Err(ExecutionError::new(
911 ExecutionErrorKind::SharedObjectOperationNotAllowed,
912 Some(
913 format!(
914 "Shared object operation on {id} not allowed: \
915 cannot be frozen, transferred, or wrapped"
916 )
917 .into(),
918 ),
919 ));
920 }
921 } else {
922 if !deleted_object_ids.contains(id) {
925 return Err(ExecutionError::new(
926 ExecutionErrorKind::SharedObjectOperationNotAllowed,
927 Some(
928 format!("Shared object operation on {id} not allowed: \
929 shared objects used by value must be re-shared if not deleted").into(),
930 ),
931 ));
932 }
933 }
934 }
935
936 let DenyListResult {
937 result,
938 num_non_gas_coin_owners,
939 } = state_view.check_coin_deny_list(&written_objects);
940 gas_charger.charge_coin_transfers(protocol_config, num_non_gas_coin_owners)?;
941 result?;
942
943 let user_events = user_events
944 .into_iter()
945 .map(|(module_id, tag, contents)| {
946 let package_id = ObjectID::new(module_id.address().into_bytes());
947 let module = Identifier::new_unchecked(module_id.name().as_str());
948 let sender = ref_context.borrow().sender();
949 Event {
950 package_id,
951 module,
952 sender,
953 type_: tag,
954 contents,
955 }
956 })
957 .collect();
958
959 Ok(ExecutionResults::V1(ExecutionResultsV1 {
960 written_objects,
961 modified_objects: loaded_runtime_objects
962 .into_iter()
963 .filter_map(|(id, loaded)| loaded.is_modified.then_some(id))
964 .collect(),
965 created_object_ids: created_object_ids.into_iter().collect(),
966 deleted_object_ids: deleted_object_ids.into_iter().collect(),
967 user_events,
968 }))
969 }
970
971 pub fn convert_vm_error(&self, error: VMError) -> ExecutionError {
973 crate::error::convert_vm_error(error, self.vm, &self.linkage_view)
974 }
975
976 pub fn convert_type_argument_error(&self, idx: usize, error: VMError) -> ExecutionError {
978 use iota_types::execution_status::TypeArgumentError;
979 use move_core_types::vm_status::StatusCode;
980 match error.major_status() {
981 StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
982 ExecutionErrorKind::TypeArityMismatch.into()
983 }
984 StatusCode::TYPE_RESOLUTION_FAILURE => ExecutionErrorKind::TypeArgumentError {
985 type_argument: idx as TypeParameterIndex,
986 kind: TypeArgumentError::TypeNotFound,
987 }
988 .into(),
989 StatusCode::CONSTRAINT_NOT_SATISFIED => ExecutionErrorKind::TypeArgumentError {
990 type_argument: idx as TypeParameterIndex,
991 kind: TypeArgumentError::ConstraintNotSatisfied,
992 }
993 .into(),
994 _ => self.convert_vm_error(error),
995 }
996 }
997
998 fn arg_is_borrowed(&self, arg: &Arg) -> bool {
1001 self.borrowed.contains_key(arg)
1002 }
1003
1004 fn arg_is_mut_borrowed(&self, arg: &Arg) -> bool {
1007 matches!(self.borrowed.get(arg), Some(true))
1008 }
1009
1010 fn borrow_mut(
1013 &mut self,
1014 arg: Arg,
1015 usage: UsageKind,
1016 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), EitherError> {
1017 self.borrow_mut_impl(arg, Some(usage))
1018 }
1019
1020 fn borrow_mut_impl(
1023 &mut self,
1024 arg: Arg,
1025 update_last_usage: Option<UsageKind>,
1026 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), EitherError> {
1027 match arg.0 {
1028 Arg_::V1(arg) => {
1029 assert_invariant!(
1030 !self.protocol_config.normalize_ptb_arguments(),
1031 "Should not be using v1 args with normalized args"
1032 );
1033 Ok(self.borrow_mut_impl_v1(arg, update_last_usage)?)
1034 }
1035 Arg_::V2(arg) => {
1036 assert_invariant!(
1037 self.protocol_config.normalize_ptb_arguments(),
1038 "Should be using only v2 args with normalized args"
1039 );
1040 Ok(self.borrow_mut_impl_v2(arg, update_last_usage)?)
1041 }
1042 }
1043 }
1044
1045 fn borrow_mut_impl_v1(
1047 &mut self,
1048 arg: Argument,
1049 update_last_usage: Option<UsageKind>,
1050 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), CommandArgumentError>
1051 {
1052 let (metadata, result_value) = match arg {
1053 Argument::Gas => (self.gas.object_metadata.as_ref(), &mut self.gas.inner),
1054 Argument::Input(i) => {
1055 let Some(input_value) = self.inputs.get_mut(i as usize) else {
1056 return Err(CommandArgumentError::IndexOutOfBounds { index: i });
1057 };
1058 (input_value.object_metadata.as_ref(), &mut input_value.inner)
1059 }
1060 Argument::Result(i) => {
1061 let Some(command_result) = self.results.get_mut(i as usize) else {
1062 return Err(CommandArgumentError::IndexOutOfBounds { index: i });
1063 };
1064 if command_result.len() != 1 {
1065 return Err(CommandArgumentError::InvalidResultArity { result: i });
1066 }
1067 (None, &mut command_result[0])
1068 }
1069 Argument::NestedResult(i, j) => {
1070 let Some(command_result) = self.results.get_mut(i as usize) else {
1071 return Err(CommandArgumentError::IndexOutOfBounds { index: i });
1072 };
1073 let Some(result_value) = command_result.get_mut(j as usize) else {
1074 return Err(CommandArgumentError::SecondaryIndexOutOfBounds {
1075 result: i,
1076 subresult: j,
1077 });
1078 };
1079 (None, result_value)
1080 }
1081 _ => {
1082 unimplemented!("a new Argument enum variant was added and needs to be handled")
1083 }
1084 };
1085 if let Some(usage) = update_last_usage {
1086 result_value.last_usage_kind = Some(usage);
1087 }
1088 Ok((metadata, &mut result_value.value))
1089 }
1090
1091 fn borrow_mut_impl_v2(
1093 &mut self,
1094 arg: NormalizedArg,
1095 update_last_usage: Option<UsageKind>,
1096 ) -> Result<(Option<&InputObjectMetadata>, &mut Option<Value>), ExecutionError> {
1097 let (metadata, result_value) = match arg {
1098 NormalizedArg::GasCoin => (self.gas.object_metadata.as_ref(), &mut self.gas.inner),
1099 NormalizedArg::Input(i) => {
1100 let input_value = self
1101 .inputs
1102 .get_mut(i as usize)
1103 .ok_or_else(|| make_invariant_violation!("bounds already checked"))?;
1104 (input_value.object_metadata.as_ref(), &mut input_value.inner)
1105 }
1106 NormalizedArg::Result(i, j) => {
1107 let result_value = self
1108 .results
1109 .get_mut(i as usize)
1110 .ok_or_else(|| make_invariant_violation!("bounds already checked"))?
1111 .get_mut(j as usize)
1112 .ok_or_else(|| make_invariant_violation!("bounds already checked"))?;
1113 (None, result_value)
1114 }
1115 };
1116 if let Some(usage) = update_last_usage {
1117 result_value.last_usage_kind = Some(usage);
1118 }
1119 Ok((metadata, &mut result_value.value))
1120 }
1121
1122 pub(crate) fn execute_function_bypass_visibility(
1127 &mut self,
1128 module: &ModuleId,
1129 function_name: &IdentStr,
1130 ty_args: Vec<Type>,
1131 args: Vec<impl Borrow<[u8]>>,
1132 tracer: &mut Option<MoveTraceBuilder>,
1133 ) -> VMResult<SerializedReturnValues> {
1134 let gas_status = self.gas_charger.move_gas_status_mut();
1135 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1136 self.vm.get_runtime().execute_function_bypass_visibility(
1137 module,
1138 function_name,
1139 ty_args,
1140 args,
1141 &mut data_store,
1142 &mut IotaGasMeter(gas_status),
1143 &mut self.native_extensions,
1144 tracer.as_mut(),
1145 )
1146 }
1147
1148 pub(crate) fn load_function(
1153 &mut self,
1154 module_id: &ModuleId,
1155 function_name: &IdentStr,
1156 type_arguments: &[Type],
1157 ) -> VMResult<LoadedFunctionInstantiation> {
1158 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1159 self.vm.get_runtime().load_function(
1160 module_id,
1161 function_name,
1162 type_arguments,
1163 &mut data_store,
1164 )
1165 }
1166
1167 pub(crate) fn make_object_value(
1172 &mut self,
1173 type_: StructTag,
1174 used_in_non_entry_move_call: bool,
1175 contents: &[u8],
1176 ) -> Result<ObjectValue, ExecutionError> {
1177 make_object_value(
1178 self.vm,
1179 &mut self.linkage_view,
1180 &self.new_packages,
1181 type_,
1182 used_in_non_entry_move_call,
1183 contents,
1184 )
1185 }
1186
1187 pub fn publish_module_bundle(
1192 &mut self,
1193 modules: Vec<Vec<u8>>,
1194 sender: AccountAddress,
1195 ) -> VMResult<()> {
1196 let mut data_store = IotaDataStore::new(&self.linkage_view, &self.new_packages);
1199 self.vm.get_runtime().publish_module_bundle(
1200 modules,
1201 sender,
1202 &mut data_store,
1203 &mut IotaGasMeter(self.gas_charger.move_gas_status_mut()),
1204 )
1205 }
1206 }
1207
1208 impl TypeTagResolver for ExecutionContext<'_, '_, '_> {
1209 fn get_type_tag(&self, type_: &Type) -> Result<TypeTag, ExecutionError> {
1212 self.vm
1213 .get_runtime()
1214 .get_type_tag(type_)
1215 .map_err(|e| self.convert_vm_error(e))
1216 .map(|tt| type_tag_core_to_sdk(&tt))
1217 }
1218 }
1219
1220 fn package_for_linkage(
1224 linkage_view: &LinkageView,
1225 package_id: ObjectID,
1226 ) -> VMResult<PackageObject> {
1227 use move_binary_format::errors::PartialVMError;
1228 use move_core_types::vm_status::StatusCode;
1229
1230 match linkage_view.get_package_object(&package_id) {
1231 Ok(Some(package)) => Ok(package),
1232 Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1233 .with_message(format!("Cannot find link context {package_id} in store"))
1234 .finish(Location::Undefined)),
1235 Err(err) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1236 .with_message(format!(
1237 "Error loading link context {package_id} from store: {err}"
1238 ))
1239 .finish(Location::Undefined)),
1240 }
1241 }
1242
1243 pub fn load_type_from_struct(
1249 vm: &MoveVM,
1250 linkage_view: &mut LinkageView,
1251 new_packages: &[MovePackage],
1252 struct_tag: &StructTag,
1253 ) -> VMResult<Type> {
1254 fn verification_error<T>(code: StatusCode) -> VMResult<T> {
1255 Err(PartialVMError::new(code).finish(Location::Undefined))
1256 }
1257
1258 let defining_id = struct_tag.address().into();
1260 let package = package_for_linkage(linkage_view, defining_id)?;
1261
1262 let original_address = linkage_view
1265 .set_linkage(package.move_package())
1266 .map_err(|e| {
1267 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1268 .with_message(e.to_string())
1269 .finish(Location::Undefined)
1270 })?;
1271
1272 let runtime_id = ModuleId::new(
1273 original_address,
1274 move_core_types::identifier::Identifier::new(struct_tag.module().as_str()).unwrap(),
1275 );
1276 let data_store = IotaDataStore::new(linkage_view, new_packages);
1277 let res = vm.get_runtime().load_type(
1278 &runtime_id,
1279 IdentStr::new(struct_tag.name().as_str()).unwrap(),
1280 &data_store,
1281 );
1282 linkage_view.reset_linkage();
1283 let (idx, struct_type) = res?;
1284
1285 let type_param_constraints = struct_type.type_param_constraints();
1287 if type_param_constraints.len() != struct_tag.type_params().len() {
1288 return verification_error(StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH);
1289 }
1290
1291 if struct_tag.type_params().is_empty() {
1292 Ok(Type::Datatype(idx))
1293 } else {
1294 let loaded_type_params = struct_tag
1295 .type_params()
1296 .iter()
1297 .map(|type_param| load_type(vm, linkage_view, new_packages, type_param))
1298 .collect::<VMResult<Vec<_>>>()?;
1299
1300 for (constraint, param) in type_param_constraints.zip(&loaded_type_params) {
1302 let abilities = vm.get_runtime().get_type_abilities(param)?;
1303 if !constraint.is_subset(abilities) {
1304 return verification_error(StatusCode::CONSTRAINT_NOT_SATISFIED);
1305 }
1306 }
1307
1308 Ok(Type::DatatypeInstantiation(Box::new((
1309 idx,
1310 loaded_type_params,
1311 ))))
1312 }
1313 }
1314
1315 pub fn load_type(
1319 vm: &MoveVM,
1320 linkage_view: &mut LinkageView,
1321 new_packages: &[MovePackage],
1322 type_tag: &TypeTag,
1323 ) -> VMResult<Type> {
1324 Ok(match type_tag {
1325 TypeTag::Bool => Type::Bool,
1326 TypeTag::U8 => Type::U8,
1327 TypeTag::U16 => Type::U16,
1328 TypeTag::U32 => Type::U32,
1329 TypeTag::U64 => Type::U64,
1330 TypeTag::U128 => Type::U128,
1331 TypeTag::U256 => Type::U256,
1332 TypeTag::Address => Type::Address,
1333 TypeTag::Signer => Type::Signer,
1334
1335 TypeTag::Vector(inner) => {
1336 Type::Vector(Box::new(load_type(vm, linkage_view, new_packages, inner)?))
1337 }
1338 TypeTag::Struct(struct_tag) => {
1339 return load_type_from_struct(vm, linkage_view, new_packages, struct_tag);
1340 }
1341 })
1342 }
1343
1344 pub(crate) fn make_object_value(
1351 vm: &MoveVM,
1352 linkage_view: &mut LinkageView,
1353 new_packages: &[MovePackage],
1354 type_: StructTag,
1355 used_in_non_entry_move_call: bool,
1356 contents: &[u8],
1357 ) -> Result<ObjectValue, ExecutionError> {
1358 let contents = if type_.is_coin() {
1359 let Ok(coin) = Coin::from_bcs_bytes(contents) else {
1360 invariant_violation!("Could not deserialize a coin")
1361 };
1362 ObjectContents::Coin(coin)
1363 } else {
1364 ObjectContents::Raw(contents.to_vec())
1365 };
1366
1367 let type_ = load_type_from_struct(vm, linkage_view, new_packages, &type_)
1368 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1369 let abilities = vm
1370 .get_runtime()
1371 .get_type_abilities(&type_)
1372 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?;
1373 let has_public_transfer = abilities.has_store();
1374 Ok(ObjectValue {
1375 type_,
1376 has_public_transfer,
1377 used_in_non_entry_move_call,
1378 contents,
1379 })
1380 }
1381
1382 impl Arg {
1383 fn is_gas_coin(&self) -> bool {
1384 match self {
1386 Arg(Arg_::V1(a)) => matches!(a, Argument::Gas),
1387 Arg(Arg_::V2(n)) => matches!(n, NormalizedArg::GasCoin),
1388 }
1389 }
1390 }
1391
1392 impl From<Arg> for Argument {
1393 fn from(arg: Arg) -> Self {
1394 match arg.0 {
1395 Arg_::V1(a) => a,
1396 Arg_::V2(normalized) => match normalized {
1397 NormalizedArg::GasCoin => Argument::Gas,
1398 NormalizedArg::Input(i) => Argument::Input(i),
1399 NormalizedArg::Result(i, j) => Argument::NestedResult(i, j),
1400 },
1401 }
1402 }
1403 }
1404
1405 pub(crate) fn value_from_object(
1410 vm: &MoveVM,
1411 linkage_view: &mut LinkageView,
1412 new_packages: &[MovePackage],
1413 object: &Object,
1414 ) -> Result<ObjectValue, ExecutionError> {
1415 let ObjectInner {
1416 data: Data::Struct(object),
1417 ..
1418 } = object.as_inner()
1419 else {
1420 invariant_violation!("Expected a Move object");
1421 };
1422
1423 let used_in_non_entry_move_call = false;
1424 make_object_value(
1425 vm,
1426 linkage_view,
1427 new_packages,
1428 object.struct_tag().clone(),
1429 used_in_non_entry_move_call,
1430 object.contents(),
1431 )
1432 }
1433
1434 fn load_object(
1436 vm: &MoveVM,
1437 state_view: &dyn ExecutionState,
1438 linkage_view: &mut LinkageView,
1439 new_packages: &[MovePackage],
1440 input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1441 override_as_immutable: bool,
1442 id: ObjectID,
1443 ) -> Result<InputValue, ExecutionError> {
1444 let Some(obj) = state_view.read_object(&id) else {
1445 invariant_violation!("Object {} does not exist yet", id);
1447 };
1448 assert_invariant!(
1450 !override_as_immutable || matches!(obj.owner, Owner::Shared(_)),
1451 "override_as_immutable should only be set for shared objects"
1452 );
1453 let is_mutable_input = match obj.owner {
1454 Owner::Address(_) => true,
1455 Owner::Shared(_) => !override_as_immutable,
1456 Owner::Immutable => false,
1457 Owner::Object(_) => {
1458 invariant_violation!("Object-owned objects cannot be inputs")
1460 }
1461 _ => unimplemented!("a new Owner enum variant was added and needs to be handled"),
1462 };
1463 let owner = obj.owner;
1464 let version = obj.version();
1465 let object_metadata = InputObjectMetadata::InputObject {
1466 id,
1467 is_mutable_input,
1468 owner,
1469 version,
1470 };
1471 let obj_value = value_from_object(vm, linkage_view, new_packages, obj)?;
1472 let contained_uids = {
1473 let fully_annotated_layout = vm
1474 .get_runtime()
1475 .type_to_fully_annotated_layout(&obj_value.type_)
1476 .map_err(|e| convert_vm_error(e, vm, linkage_view))?;
1477 let mut bytes = vec![];
1478 obj_value.write_bcs_bytes(&mut bytes, None)?;
1479 match get_all_uids(&fully_annotated_layout, &bytes) {
1480 Err(e) => {
1481 invariant_violation!("Unable to retrieve UIDs for object. Got error: {e}")
1482 }
1483 Ok(uids) => uids,
1484 }
1485 };
1486 let runtime_input = object_runtime::InputObject {
1487 contained_uids,
1488 owner,
1489 version,
1490 };
1491 let prev = input_object_map.insert(id, runtime_input);
1492 assert_invariant!(prev.is_none(), "Duplicate input object {}", id);
1494 Ok(InputValue::new_object(object_metadata, obj_value))
1495 }
1496
1497 fn load_call_arg(
1499 vm: &MoveVM,
1500 state_view: &dyn ExecutionState,
1501 linkage_view: &mut LinkageView,
1502 new_packages: &[MovePackage],
1503 input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1504 call_arg: CallArg,
1505 ) -> Result<InputValue, ExecutionError> {
1506 Ok(match call_arg {
1507 CallArg::Pure(value) => InputValue::new_raw(RawValueType::Any, value),
1508 other => load_object_arg(
1509 vm,
1510 state_view,
1511 linkage_view,
1512 new_packages,
1513 input_object_map,
1514 other,
1515 )?,
1516 })
1517 }
1518
1519 fn load_object_arg(
1522 vm: &MoveVM,
1523 state_view: &dyn ExecutionState,
1524 linkage_view: &mut LinkageView,
1525 new_packages: &[MovePackage],
1526 input_object_map: &mut BTreeMap<ObjectID, object_runtime::InputObject>,
1527 obj_arg: CallArg,
1528 ) -> Result<InputValue, ExecutionError> {
1529 match obj_arg {
1530 CallArg::ImmutableOrOwned(object_ref) => load_object(
1531 vm,
1532 state_view,
1533 linkage_view,
1534 new_packages,
1535 input_object_map,
1536 false,
1538 object_ref.object_id,
1539 ),
1540 CallArg::Shared(SharedObjectRef {
1541 object_id: id,
1542 mutable,
1543 ..
1544 }) => load_object(
1545 vm,
1546 state_view,
1547 linkage_view,
1548 new_packages,
1549 input_object_map,
1550 !mutable,
1552 id,
1553 ),
1554 CallArg::Receiving(object_ref) => Ok(InputValue::new_receiving_object(
1555 object_ref.object_id,
1556 object_ref.version,
1557 )),
1558 CallArg::Pure(_) => Err(ExecutionError::invariant_violation(
1559 "unexpected pure CallArg in load_object_arg",
1560 )),
1561 _ => Err(ExecutionError::invariant_violation(
1562 "a new CallArg enum variant was added and needs to be handled",
1563 )),
1564 }
1565 }
1566
1567 fn add_additional_write(
1569 additional_writes: &mut BTreeMap<ObjectID, AdditionalWrite>,
1570 owner: Owner,
1571 object_value: ObjectValue,
1572 ) -> Result<(), ExecutionError> {
1573 let ObjectValue {
1574 type_, contents, ..
1575 } = object_value;
1576 let bytes = match contents {
1577 ObjectContents::Coin(coin) => coin.to_bcs_bytes(),
1578 ObjectContents::Raw(bytes) => bytes,
1579 };
1580 let object_id =
1581 ObjectID::from_bytes(bytes.get(..ObjectID::LENGTH).ok_or_else(|| {
1582 ExecutionError::invariant_violation("No id for Raw object bytes")
1583 })?)
1584 .expect("ObjectID::LENGTH bytes is always a valid ObjectID");
1585 let additional_write = AdditionalWrite {
1586 recipient: owner,
1587 type_,
1588 bytes,
1589 };
1590 additional_writes.insert(object_id, additional_write);
1591 Ok(())
1592 }
1593
1594 fn refund_max_gas_budget(
1598 additional_writes: &mut BTreeMap<ObjectID, AdditionalWrite>,
1599 gas_charger: &mut GasCharger,
1600 gas_id: ObjectID,
1601 ) -> Result<(), ExecutionError> {
1602 let Some(AdditionalWrite { bytes, .. }) = additional_writes.get_mut(&gas_id) else {
1603 invariant_violation!("Gas object cannot be wrapped or destroyed")
1604 };
1605 let Ok(mut coin) = Coin::from_bcs_bytes(bytes) else {
1606 invariant_violation!("Gas object must be a coin")
1607 };
1608 let Some(new_balance) = coin.balance.value().checked_add(gas_charger.gas_budget()) else {
1609 return Err(ExecutionError::new_with_source(
1610 ExecutionErrorKind::CoinBalanceOverflow,
1611 "Gas coin too large after returning the max gas budget",
1612 ));
1613 };
1614 coin.balance = Balance::new(new_balance);
1615 *bytes = coin.to_bcs_bytes();
1616 Ok(())
1617 }
1618
1619 fn create_written_object(
1621 vm: &MoveVM,
1622 linkage_view: &LinkageView,
1623 protocol_config: &ProtocolConfig,
1624 objects_modified_at: &BTreeMap<ObjectID, LoadedRuntimeObject>,
1625 id: ObjectID,
1626 type_: Type,
1627 contents: Vec<u8>,
1628 ) -> Result<MoveObject, ExecutionError> {
1629 debug_assert_eq!(
1630 id,
1631 ObjectID::from_bytes(&contents[..ObjectID::LENGTH])
1632 .expect("object contents should start with an id")
1633 );
1634 let old_obj_ver = objects_modified_at
1635 .get(&id)
1636 .map(|obj: &LoadedRuntimeObject| obj.version);
1637
1638 let type_tag = type_tag_core_to_sdk(
1639 &vm.get_runtime()
1640 .get_type_tag(&type_)
1641 .map_err(|e| crate::error::convert_vm_error(e, vm, linkage_view))?,
1642 );
1643
1644 let struct_tag = match type_tag {
1645 TypeTag::Struct(inner) => *inner,
1646 _ => invariant_violation!("Non struct type for object"),
1647 };
1648 MoveObject::new_from_execution(
1649 struct_tag,
1650 old_obj_ver.unwrap_or_default(),
1651 contents,
1652 protocol_config,
1653 )
1654 }
1655
1656 pub(crate) struct IotaDataStore<'state, 'a> {
1664 linkage_view: &'a LinkageView<'state>,
1665 new_packages: &'a [MovePackage],
1666 }
1667
1668 impl<'state, 'a> IotaDataStore<'state, 'a> {
1669 pub(crate) fn new(
1670 linkage_view: &'a LinkageView<'state>,
1671 new_packages: &'a [MovePackage],
1672 ) -> Self {
1673 Self {
1674 linkage_view,
1675 new_packages,
1676 }
1677 }
1678
1679 fn get_module(&self, module_id: &ModuleId) -> Option<&Vec<u8>> {
1680 for package in self.new_packages {
1681 if package.id != ObjectID::from(module_id.address().into_bytes()) {
1682 continue;
1683 }
1684
1685 let module =
1686 package.get_module(&Identifier::new_unchecked(module_id.name().as_str()));
1687
1688 if module.is_some() {
1689 return module;
1690 }
1691 }
1692 None
1693 }
1694 }
1695
1696 impl DataStore for IotaDataStore<'_, '_> {
1700 fn link_context(&self) -> AccountAddress {
1701 self.linkage_view.link_context()
1702 }
1703
1704 fn relocate(&self, module_id: &ModuleId) -> PartialVMResult<ModuleId> {
1705 self.linkage_view.relocate(module_id).map_err(|err| {
1706 PartialVMError::new(StatusCode::LINKER_ERROR)
1707 .with_message(format!("Error relocating {module_id}: {err:?}"))
1708 })
1709 }
1710
1711 fn defining_module(
1712 &self,
1713 runtime_id: &ModuleId,
1714 struct_: &IdentStr,
1715 ) -> PartialVMResult<ModuleId> {
1716 self.linkage_view
1717 .defining_module(runtime_id, struct_)
1718 .map_err(|err| {
1719 PartialVMError::new(StatusCode::LINKER_ERROR).with_message(format!(
1720 "Error finding defining module for {runtime_id}::{struct_}: {err:?}"
1721 ))
1722 })
1723 }
1724
1725 fn load_module(&self, module_id: &ModuleId) -> VMResult<Vec<u8>> {
1726 if let Some(bytes) = self.get_module(module_id) {
1727 return Ok(bytes.clone());
1728 }
1729 match self.linkage_view.get_module(module_id) {
1730 Ok(Some(bytes)) => Ok(bytes),
1731 Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
1732 .with_message(format!("Cannot find {module_id:?} in data cache"))
1733 .finish(Location::Undefined)),
1734 Err(err) => {
1735 let msg = format!("Unexpected storage error: {err:?}");
1736 Err(
1737 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
1738 .with_message(msg)
1739 .finish(Location::Undefined),
1740 )
1741 }
1742 }
1743 }
1744
1745 fn publish_module(&mut self, _module_id: &ModuleId, _blob: Vec<u8>) -> VMResult<()> {
1746 Ok(())
1749 }
1750 }
1751
1752 enum EitherError {
1753 CommandArgument(CommandArgumentError),
1754 Execution(ExecutionError),
1755 }
1756
1757 impl From<ExecutionError> for EitherError {
1758 fn from(e: ExecutionError) -> Self {
1759 EitherError::Execution(e)
1760 }
1761 }
1762
1763 impl From<CommandArgumentError> for EitherError {
1764 fn from(e: CommandArgumentError) -> Self {
1765 EitherError::CommandArgument(e)
1766 }
1767 }
1768
1769 impl EitherError {
1770 fn into_execution_error(self, command_index: usize) -> ExecutionError {
1771 match self {
1772 EitherError::CommandArgument(e) => command_argument_error(e, command_index),
1773 EitherError::Execution(e) => e,
1774 }
1775 }
1776 }
1777}