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