1use crate::{
9 data_store::{PackageStore, cached_package_store::CachedPackageStore},
10 execution_value::ExecutionState,
11 static_programmable_transactions::{
12 execution::context::subst_signature,
13 linkage::{analysis::LinkageAnalyzer, resolved_linkage::ExecutableLinkage},
14 loading::ast::{self as L, Datatype, LoadedFunction, LoadedFunctionInstantiation, Type},
15 },
16};
17use move_binary_format::{
18 errors::VMError,
19 file_format::{Ability, AbilitySet, TypeParameterIndex},
20};
21use move_core_types::{
22 annotated_value,
23 identifier::IdentStr,
24 language_storage::{ModuleId, StructTag},
25 resolver::IntraPackageName,
26 runtime_value::{self, MoveTypeLayout},
27 vm_status::StatusCode,
28};
29use move_vm_runtime::{
30 execution::{self as vm_runtime, vm::MoveVM},
31 runtime::MoveRuntime,
32};
33use std::{cell::OnceCell, rc::Rc};
34use sui_protocol_config::ProtocolConfig;
35use sui_types::{
36 Identifier, SUI_FRAMEWORK_PACKAGE_ID, TypeTag,
37 balance::RESOLVED_BALANCE_STRUCT,
38 base_types::{ObjectID, TxContext},
39 coin::RESOLVED_COIN_STRUCT,
40 error::ExecutionError,
41 execution_status::{ExecutionErrorKind, TypeArgumentError},
42 funds_accumulator::RESOLVED_WITHDRAWAL_STRUCT,
43 gas_coin::GasCoin,
44 move_package::{UpgradeCap, UpgradeReceipt, UpgradeTicket},
45 object::Object,
46 type_input::{StructInput, TypeInput},
47};
48
49pub struct Env<'pc, 'vm, 'state, 'linkage, 'extensions> {
50 pub protocol_config: &'pc ProtocolConfig,
51 pub vm: &'vm MoveRuntime,
52 pub state_view: &'state mut dyn ExecutionState,
53 pub linkable_store: &'linkage CachedPackageStore<'state, 'vm>,
54 pub linkage_analysis: &'linkage LinkageAnalyzer,
55 gas_coin_type: OnceCell<Type>,
56 upgrade_ticket_type: OnceCell<Type>,
57 upgrade_receipt_type: OnceCell<Type>,
58 upgrade_cap_type: OnceCell<Type>,
59 tx_context_type: OnceCell<Type>,
60 input_type_resolution_vm: &'linkage MoveVM<'extensions>,
64}
65
66macro_rules! get_or_init_ty {
67 ($env:expr, $ident:ident, $tag:expr) => {{
68 let env = $env;
69 if env.$ident.get().is_none() {
70 let tag = $tag;
71 let ty = env.load_type_from_struct(&tag)?;
72 env.$ident.set(ty.clone()).unwrap();
73 }
74 Ok(env.$ident.get().unwrap().clone())
75 }};
76}
77
78impl<'pc, 'vm, 'state, 'linkage, 'extensions> Env<'pc, 'vm, 'state, 'linkage, 'extensions> {
79 pub fn new(
80 protocol_config: &'pc ProtocolConfig,
81 vm: &'vm MoveRuntime,
82 state_view: &'state mut dyn ExecutionState,
83 linkable_store: &'linkage CachedPackageStore<'state, 'vm>,
84 linkage_analysis: &'linkage LinkageAnalyzer,
85 input_type_resolution_vm: &'linkage MoveVM<'extensions>,
86 ) -> Self {
87 Self {
88 protocol_config,
89 vm,
90 state_view,
91 linkable_store,
92 linkage_analysis,
93 gas_coin_type: OnceCell::new(),
94 upgrade_ticket_type: OnceCell::new(),
95 upgrade_receipt_type: OnceCell::new(),
96 upgrade_cap_type: OnceCell::new(),
97 tx_context_type: OnceCell::new(),
98 input_type_resolution_vm,
99 }
100 }
101
102 pub fn convert_linked_vm_error(
103 &self,
104 e: VMError,
105 linkage: &ExecutableLinkage,
106 ) -> ExecutionError {
107 convert_vm_error(e, self.linkable_store, Some(linkage), self.protocol_config)
108 }
109
110 pub fn convert_vm_error(&self, e: VMError) -> ExecutionError {
111 convert_vm_error(e, self.linkable_store, None, self.protocol_config)
112 }
113
114 pub fn convert_type_argument_error(
115 &self,
116 idx: usize,
117 e: VMError,
118 linkage: &ExecutableLinkage,
119 ) -> ExecutionError {
120 use move_core_types::vm_status::StatusCode;
121 let argument_idx = match checked_as!(idx, TypeParameterIndex) {
122 Err(e) => return e,
123 Ok(v) => v,
124 };
125 match e.major_status() {
126 StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
127 ExecutionErrorKind::TypeArityMismatch.into()
128 }
129 StatusCode::EXTERNAL_RESOLUTION_REQUEST_ERROR => {
130 ExecutionErrorKind::TypeArgumentError {
131 argument_idx,
132 kind: TypeArgumentError::TypeNotFound,
133 }
134 .into()
135 }
136 StatusCode::CONSTRAINT_NOT_SATISFIED => ExecutionErrorKind::TypeArgumentError {
137 argument_idx,
138 kind: TypeArgumentError::ConstraintNotSatisfied,
139 }
140 .into(),
141 _ => self.convert_linked_vm_error(e, linkage),
142 }
143 }
144
145 pub fn fully_annotated_layout(
146 &self,
147 ty: &Type,
148 ) -> Result<annotated_value::MoveTypeLayout, ExecutionError> {
149 let tag: TypeTag = ty.clone().try_into().map_err(|s| {
150 ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
151 })?;
152 let objects = tag.all_addresses();
153 let tag_linkage = ExecutableLinkage::type_linkage(
154 self.linkage_analysis.config().clone(),
155 objects.into_iter().map(ObjectID::from),
156 self.linkable_store,
157 )?;
158 self.input_type_resolution_vm
159 .annotated_type_layout(&tag)
160 .map_err(|e| self.convert_linked_vm_error(e, &tag_linkage))
161 }
162
163 pub fn runtime_layout(
164 &self,
165 ty: &Type,
166 ) -> Result<runtime_value::MoveTypeLayout, ExecutionError> {
167 let tag: TypeTag = ty.clone().try_into().map_err(|s| {
168 ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
169 })?;
170 let objects = tag.all_addresses();
171 let tag_linkage = ExecutableLinkage::type_linkage(
172 self.linkage_analysis.config().clone(),
173 objects.into_iter().map(ObjectID::from),
174 self.linkable_store,
175 )?;
176 self.input_type_resolution_vm
177 .runtime_type_layout(&tag)
178 .map_err(|e| self.convert_linked_vm_error(e, &tag_linkage))
179 }
180
181 pub fn load_framework_function(
182 &self,
183 module: &IdentStr,
184 function: &IdentStr,
185 type_arguments: Vec<Type>,
186 ) -> Result<LoadedFunction, ExecutionError> {
187 self.load_function(
188 SUI_FRAMEWORK_PACKAGE_ID,
189 module.to_string(),
190 function.to_string(),
191 type_arguments,
192 )
193 }
194
195 pub fn load_function(
196 &self,
197 package: ObjectID,
198 module: String,
199 function: String,
200 type_arguments: Vec<Type>,
201 ) -> Result<LoadedFunction, ExecutionError> {
202 let module = to_identifier(module)?;
203 let name = to_identifier(function)?;
204
205 let linkage = self.linkage_analysis.compute_call_linkage(
206 &package,
207 module.as_ident_str(),
208 name.as_ident_str(),
209 &type_arguments,
210 self.linkable_store,
211 )?;
212
213 let Some(original_id) = linkage.0.resolve_to_original_id(&package) else {
214 invariant_violation!(
215 "Package ID {:?} is not found in linkage generated for that package",
216 package
217 );
218 };
219 let version_mid = ModuleId::new(package.into(), module.clone());
220 let original_mid = ModuleId::new(original_id.into(), module);
221 let loaded_type_arguments = type_arguments
222 .iter()
223 .enumerate()
224 .map(|(idx, ty)| self.load_vm_type_argument_from_adapter_type(idx, ty))
225 .collect::<Result<Vec<_>, _>>()?;
226 let vm = self
230 .vm
231 .make_vm(
232 &self.linkable_store.package_store,
233 linkage.linkage_context()?,
234 )
235 .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
236 let runtime_signature = vm
237 .function_information(&original_mid, name.as_ident_str(), &loaded_type_arguments)
238 .map_err(|e| {
239 if e.major_status() == StatusCode::EXTERNAL_RESOLUTION_REQUEST_ERROR {
240 ExecutionError::new_with_source(
241 ExecutionErrorKind::FunctionNotFound,
242 format!(
243 "Could not resolve function '{}' in module '{}'",
244 name, &version_mid,
245 ),
246 )
247 } else {
248 self.convert_linked_vm_error(e, &linkage)
249 }
250 })?;
251 let runtime_signature = subst_signature(runtime_signature, &loaded_type_arguments)
252 .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
253 let parameters = runtime_signature
254 .parameters
255 .into_iter()
256 .map(|ty| self.adapter_type_from_vm_type(&vm, &ty))
257 .collect::<Result<Vec<_>, _>>()?;
258 let return_ = runtime_signature
259 .return_
260 .into_iter()
261 .map(|ty| self.adapter_type_from_vm_type(&vm, &ty))
262 .collect::<Result<Vec<_>, _>>()?;
263 let signature = LoadedFunctionInstantiation {
264 parameters,
265 return_,
266 };
267 Ok(LoadedFunction {
268 version_mid,
269 original_mid,
270 name,
271 type_arguments,
272 signature,
273 linkage,
274 instruction_length: runtime_signature.instruction_count,
275 definition_index: runtime_signature.index,
276 visibility: runtime_signature.visibility,
277 is_entry: runtime_signature.is_entry,
278 is_native: runtime_signature.is_native,
279 })
280 }
281
282 pub fn load_type_input(&self, idx: usize, ty: TypeInput) -> Result<Type, ExecutionError> {
283 let vm_type = self.load_vm_type_from_type_input(idx, ty)?;
284 self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
285 }
286
287 pub fn load_type_tag(&self, idx: usize, ty: &TypeTag) -> Result<Type, ExecutionError> {
288 let vm_type = self.load_vm_type_from_type_tag(Some(idx), ty)?;
289 self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
290 }
291
292 pub fn load_type_from_struct(&self, tag: &StructTag) -> Result<Type, ExecutionError> {
294 let vm_type =
295 self.load_vm_type_from_type_tag(None, &TypeTag::Struct(Box::new(tag.clone())))?;
296 self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
297 }
298
299 pub fn type_layout_for_struct(
300 &self,
301 tag: &StructTag,
302 ) -> Result<MoveTypeLayout, ExecutionError> {
303 let ty: Type = self.load_type_from_struct(tag)?;
304 self.runtime_layout(&ty)
305 }
306
307 pub fn gas_coin_type(&self) -> Result<Type, ExecutionError> {
308 get_or_init_ty!(self, gas_coin_type, GasCoin::type_())
309 }
310
311 pub fn upgrade_ticket_type(&self) -> Result<Type, ExecutionError> {
312 get_or_init_ty!(self, upgrade_ticket_type, UpgradeTicket::type_())
313 }
314
315 pub fn upgrade_receipt_type(&self) -> Result<Type, ExecutionError> {
316 get_or_init_ty!(self, upgrade_receipt_type, UpgradeReceipt::type_())
317 }
318
319 pub fn upgrade_cap_type(&self) -> Result<Type, ExecutionError> {
320 get_or_init_ty!(self, upgrade_cap_type, UpgradeCap::type_())
321 }
322
323 pub fn tx_context_type(&self) -> Result<Type, ExecutionError> {
324 get_or_init_ty!(self, tx_context_type, TxContext::type_())
325 }
326
327 pub fn coin_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
328 const COIN_ABILITIES: AbilitySet =
329 AbilitySet::singleton(Ability::Key).union(AbilitySet::singleton(Ability::Store));
330 let (a, m, n) = RESOLVED_COIN_STRUCT;
331 let module = ModuleId::new(*a, m.to_owned());
332 Ok(Type::Datatype(Rc::new(Datatype {
333 abilities: COIN_ABILITIES,
334 module,
335 name: n.to_owned(),
336 type_arguments: vec![inner_type],
337 })))
338 }
339
340 pub fn balance_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
341 const BALANCE_ABILITIES: AbilitySet = AbilitySet::singleton(Ability::Store);
342 let (a, m, n) = RESOLVED_BALANCE_STRUCT;
343 let module = ModuleId::new(*a, m.to_owned());
344 Ok(Type::Datatype(Rc::new(Datatype {
345 abilities: BALANCE_ABILITIES,
346 module,
347 name: n.to_owned(),
348 type_arguments: vec![inner_type],
349 })))
350 }
351
352 pub fn withdrawal_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
353 const WITHDRAWAL_ABILITIES: AbilitySet = AbilitySet::singleton(Ability::Drop);
354 let (a, m, n) = RESOLVED_WITHDRAWAL_STRUCT;
355 let module = ModuleId::new(*a, m.to_owned());
356 Ok(Type::Datatype(Rc::new(Datatype {
357 abilities: WITHDRAWAL_ABILITIES,
358 module,
359 name: n.to_owned(),
360 type_arguments: vec![inner_type],
361 })))
362 }
363
364 pub fn vector_type(&self, element_type: Type) -> Result<Type, ExecutionError> {
365 let abilities = AbilitySet::polymorphic_abilities(
366 AbilitySet::VECTOR,
367 [false],
368 [element_type.abilities()],
369 )
370 .map_err(|e| {
371 ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
372 })?;
373 Ok(Type::Vector(Rc::new(L::Vector {
374 abilities,
375 element_type,
376 })))
377 }
378
379 pub fn read_object(&self, id: &ObjectID) -> Result<&Object, ExecutionError> {
380 let Some(obj) = self.state_view.read_object(id) else {
381 invariant_violation!("Object {:?} does not exist", id);
383 };
384 Ok(obj)
385 }
386
387 pub fn load_vm_type_argument_from_adapter_type(
389 &self,
390 idx: usize,
391 ty: &Type,
392 ) -> Result<vm_runtime::Type, ExecutionError> {
393 self.load_vm_type_from_adapter_type(Some(idx), ty)
394 }
395
396 fn load_vm_type_from_adapter_type(
397 &self,
398 type_arg_idx: Option<usize>,
399 ty: &Type,
400 ) -> Result<vm_runtime::Type, ExecutionError> {
401 let tag: TypeTag = ty.clone().try_into().map_err(|s| {
402 ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
403 })?;
404 self.load_vm_type_from_type_tag(type_arg_idx, &tag)
405 }
406
407 fn load_vm_type_from_type_tag(
409 &self,
410 type_arg_idx: Option<usize>,
411 tag: &TypeTag,
412 ) -> Result<vm_runtime::Type, ExecutionError> {
413 fn execution_error(
414 env: &Env,
415 type_arg_idx: Option<usize>,
416 e: VMError,
417 linkage: &ExecutableLinkage,
418 ) -> ExecutionError {
419 if let Some(idx) = type_arg_idx {
420 env.convert_type_argument_error(idx, e, linkage)
421 } else {
422 env.convert_linked_vm_error(e, linkage)
423 }
424 }
425
426 let objects = tag.all_addresses();
427
428 let tag_linkage = ExecutableLinkage::type_linkage(
429 self.linkage_analysis.config().clone(),
430 objects.iter().map(|a| ObjectID::from(*a)),
431 self.linkable_store,
432 )?;
433 let ty = self
434 .input_type_resolution_vm
435 .load_type(tag)
436 .map_err(|e| execution_error(self, type_arg_idx, e, &tag_linkage))?;
437 Ok(ty)
438 }
439
440 pub(crate) fn adapter_type_from_vm_type(
442 &self,
443 vm: &MoveVM,
444 vm_type: &vm_runtime::Type,
445 ) -> Result<Type, ExecutionError> {
446 use vm_runtime as VRT;
447
448 Ok(match vm_type {
449 VRT::Type::Bool => Type::Bool,
450 VRT::Type::U8 => Type::U8,
451 VRT::Type::U16 => Type::U16,
452 VRT::Type::U32 => Type::U32,
453 VRT::Type::U64 => Type::U64,
454 VRT::Type::U128 => Type::U128,
455 VRT::Type::U256 => Type::U256,
456 VRT::Type::Address => Type::Address,
457 VRT::Type::Signer => Type::Signer,
458
459 VRT::Type::Reference(ref_ty) => {
460 let inner_ty = self.adapter_type_from_vm_type(vm, ref_ty)?;
461 Type::Reference(false, Rc::new(inner_ty))
462 }
463 VRT::Type::MutableReference(ref_ty) => {
464 let inner_ty = self.adapter_type_from_vm_type(vm, ref_ty)?;
465 Type::Reference(true, Rc::new(inner_ty))
466 }
467
468 VRT::Type::Vector(inner) => {
469 let element_type = self.adapter_type_from_vm_type(vm, inner)?;
470 self.vector_type(element_type)?
471 }
472 VRT::Type::Datatype(_) => {
473 let type_information = vm
474 .type_information(vm_type)
475 .map_err(|e| self.convert_vm_error(e))?;
476 let Some(data_type_info) = type_information.datatype_info else {
477 invariant_violation!("Expected datatype info for datatype type {:?}", vm_type);
478 };
479 let datatype = Datatype {
480 abilities: type_information.abilities,
481 module: ModuleId::new(data_type_info.defining_id, data_type_info.module_name),
482 name: data_type_info.type_name,
483 type_arguments: vec![],
484 };
485 Type::Datatype(Rc::new(datatype))
486 }
487 ty @ VRT::Type::DatatypeInstantiation(inst) => {
488 let (_, type_arguments) = &**inst;
489 let type_information = vm
490 .type_information(ty)
491 .map_err(|e| self.convert_vm_error(e))?;
492 let Some(data_type_info) = type_information.datatype_info else {
493 invariant_violation!("Expected datatype info for datatype type {:?}", vm_type);
494 };
495
496 let abilities = type_information.abilities;
497 let module = ModuleId::new(data_type_info.defining_id, data_type_info.module_name);
498 let name = data_type_info.type_name;
499 let type_arguments = type_arguments
500 .iter()
501 .map(|t| self.adapter_type_from_vm_type(vm, t))
502 .collect::<Result<Vec<_>, _>>()?;
503
504 Type::Datatype(Rc::new(Datatype {
505 abilities,
506 module,
507 name,
508 type_arguments,
509 }))
510 }
511
512 VRT::Type::TyParam(_) => {
513 invariant_violation!(
514 "Unexpected type parameter in VM type: {:?}. This should not happen as we should \
515 have resolved all type parameters before this point.",
516 vm_type
517 );
518 }
519 })
520 }
521
522 fn load_vm_type_from_type_input(
526 &self,
527 type_arg_idx: usize,
528 ty: TypeInput,
529 ) -> Result<vm_runtime::Type, ExecutionError> {
530 fn to_type_tag_internal(
531 env: &Env,
532 type_arg_idx: usize,
533 ty: TypeInput,
534 ) -> Result<TypeTag, ExecutionError> {
535 Ok(match ty {
536 TypeInput::Bool => TypeTag::Bool,
537 TypeInput::U8 => TypeTag::U8,
538 TypeInput::U16 => TypeTag::U16,
539 TypeInput::U32 => TypeTag::U32,
540 TypeInput::U64 => TypeTag::U64,
541 TypeInput::U128 => TypeTag::U128,
542 TypeInput::U256 => TypeTag::U256,
543 TypeInput::Address => TypeTag::Address,
544 TypeInput::Signer => TypeTag::Signer,
545 TypeInput::Vector(type_input) => {
546 let inner = to_type_tag_internal(env, type_arg_idx, *type_input)?;
547 TypeTag::Vector(Box::new(inner))
548 }
549 TypeInput::Struct(struct_input) => {
550 let StructInput {
551 address,
552 module,
553 name,
554 type_params,
555 } = *struct_input;
556
557 let pkg = env
558 .linkable_store
559 .get_package(&address.into())
560 .ok()
561 .flatten()
562 .ok_or_else(|| {
563 let argument_idx = match checked_as!(type_arg_idx, u16) {
564 Err(e) => return e,
565 Ok(v) => v,
566 };
567 ExecutionError::from_kind(ExecutionErrorKind::TypeArgumentError {
568 argument_idx,
569 kind: TypeArgumentError::TypeNotFound,
570 })
571 })?;
572 let module = to_identifier(module)?;
573 let name = to_identifier(name)?;
574 let tid = IntraPackageName {
575 module_name: module,
576 type_name: name,
577 };
578 let Some(resolved_address) = pkg.type_origin_table().get(&tid).cloned() else {
579 return Err(ExecutionError::from_kind(
580 ExecutionErrorKind::TypeArgumentError {
581 argument_idx: checked_as!(type_arg_idx, u16)?,
582 kind: TypeArgumentError::TypeNotFound,
583 },
584 ));
585 };
586
587 let tys = type_params
588 .into_iter()
589 .map(|tp| to_type_tag_internal(env, type_arg_idx, tp))
590 .collect::<Result<Vec<_>, _>>()?;
591 TypeTag::Struct(Box::new(StructTag {
592 address: resolved_address,
593 module: tid.module_name,
594 name: tid.type_name,
595 type_params: tys,
596 }))
597 }
598 })
599 }
600 let tag = to_type_tag_internal(self, type_arg_idx, ty)?;
601 self.load_vm_type_from_type_tag(Some(type_arg_idx), &tag)
602 }
603}
604
605fn to_identifier(name: String) -> Result<Identifier, ExecutionError> {
606 Identifier::new(name).map_err(|e| {
607 ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
608 })
609}
610
611fn convert_vm_error(
612 error: VMError,
613 store: &dyn PackageStore,
614 linkage: Option<&ExecutableLinkage>,
615 _protocol_config: &ProtocolConfig,
616) -> ExecutionError {
617 use crate::error::convert_vm_error_impl;
618 convert_vm_error_impl(
619 error,
620 &|id| {
621 debug_assert!(
622 linkage.is_some(),
623 "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
624 );
625 linkage
626 .and_then(|linkage| {
627 linkage
628 .0
629 .linkage
630 .get(&(*id.address()).into())
631 .map(|new_id| ModuleId::new((*new_id).into(), id.name().to_owned()))
632 })
633 .unwrap_or_else(|| id.clone())
634 },
635 &|id, function| {
637 debug_assert!(
638 linkage.is_some(),
639 "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
640 );
641 linkage.and_then(|linkage| {
642 let version_id = linkage
643 .0
644 .linkage
645 .get(&(*id.address()).into())
646 .cloned()
647 .unwrap_or_else(|| ObjectID::from_address(*id.address()));
648 store.get_package(&version_id).ok().flatten().and_then(|p| {
649 p.modules().get(id).map(|module| {
650 let module = module.compiled_module();
651 let fdef = module.function_def_at(function);
652 let fhandle = module.function_handle_at(fdef.function);
653 module.identifier_at(fhandle.name).to_string()
654 })
655 })
656 })
657 },
658 )
659}