1use crate::execution_status::PackageUpgradeError;
5use crate::{
6 SUI_FRAMEWORK_ADDRESS,
7 base_types::{ObjectID, SequenceNumber},
8 crypto::DefaultHash,
9 error::{ExecutionError, SuiErrorKind, SuiResult},
10 execution_status::ExecutionErrorKind,
11 id::{ID, UID},
12 object::OBJECT_START_VERSION,
13};
14use fastcrypto::hash::HashFunction;
15use move_binary_format::binary_config::BinaryConfig;
16use move_binary_format::file_format::CompiledModule;
17use move_binary_format::file_format_common::VERSION_6;
18use move_binary_format::normalized;
19use move_core_types::language_storage::ModuleId;
20use move_core_types::resolver::{IntraPackageName, SerializedPackage};
21use move_core_types::{
22 account_address::AccountAddress,
23 ident_str,
24 identifier::{IdentStr, Identifier},
25 language_storage::StructTag,
26};
27use once_cell::sync::Lazy;
28use schemars::JsonSchema;
29use serde::{Deserialize, Serialize};
30use serde_with::Bytes;
31use serde_with::serde_as;
32use std::collections::{BTreeMap, BTreeSet};
33use std::hash::Hash;
34use sui_protocol_config::ProtocolConfig;
35
36pub const PACKAGE_MODULE_NAME: &IdentStr = ident_str!("package");
42pub const UPGRADECAP_STRUCT_NAME: &IdentStr = ident_str!("UpgradeCap");
43pub const UPGRADETICKET_STRUCT_NAME: &IdentStr = ident_str!("UpgradeTicket");
44pub const UPGRADERECEIPT_STRUCT_NAME: &IdentStr = ident_str!("UpgradeReceipt");
45
46const DEFAULT_MAX_DISASSEMBLED_MODULE_SIZE: Option<usize> = Some(1024 * 1024);
48
49const MAX_DISASSEMBLED_MODULE_SIZE_ENV: &str = "MAX_DISASSEMBLED_MODULE_SIZE";
50pub static MAX_DISASSEMBLED_MODULE_SIZE: Lazy<Option<usize>> = Lazy::new(|| {
51 let max_bound_opt: Option<usize> = std::env::var(MAX_DISASSEMBLED_MODULE_SIZE_ENV)
52 .ok()
53 .and_then(|s| s.parse().ok());
54 match max_bound_opt {
55 Some(0) => None,
56 Some(max_bound) => Some(max_bound),
57 None => DEFAULT_MAX_DISASSEMBLED_MODULE_SIZE,
58 }
59});
60
61#[derive(Clone, Debug)]
62pub struct FnInfo {
64 pub is_test: bool,
66}
67
68#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
69pub struct FnInfoKey {
71 pub fn_name: String,
72 pub mod_addr: AccountAddress,
73}
74
75pub type FnInfoMap = BTreeMap<FnInfoKey, FnInfo>;
77
78#[derive(
80 Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, Hash, JsonSchema,
81)]
82pub struct TypeOrigin {
83 pub module_name: String,
84 #[serde(alias = "struct_name")]
86 pub datatype_name: String,
87 pub package: ObjectID,
88}
89
90#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash, JsonSchema)]
92pub struct UpgradeInfo {
93 pub upgraded_id: ObjectID,
95 pub upgraded_version: SequenceNumber,
97}
98
99#[serde_as]
101#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)]
102pub struct MovePackage {
103 id: ObjectID,
104 version: SequenceNumber,
115 #[serde_as(as = "BTreeMap<_, Bytes>")]
117 module_map: BTreeMap<String, Vec<u8>>,
118
119 type_origin_table: Vec<TypeOrigin>,
122
123 linkage_table: BTreeMap<ObjectID, UpgradeInfo>,
126}
127
128#[repr(u8)]
132#[derive(derive_more::Display, Debug, Clone, Copy)]
133pub enum UpgradePolicy {
134 #[display("COMPATIBLE")]
135 Compatible = 0,
136 #[display("ADDITIVE")]
137 Additive = 128,
138 #[display("DEP_ONLY")]
139 DepOnly = 192,
140}
141
142impl UpgradePolicy {
143 pub const COMPATIBLE: u8 = Self::Compatible as u8;
145 pub const ADDITIVE: u8 = Self::Additive as u8;
146 pub const DEP_ONLY: u8 = Self::DepOnly as u8;
147
148 pub fn is_valid_policy(policy: &u8) -> bool {
149 Self::try_from(*policy).is_ok()
150 }
151}
152
153impl TryFrom<u8> for UpgradePolicy {
154 type Error = ();
155 fn try_from(value: u8) -> Result<Self, Self::Error> {
156 match value {
157 x if x == Self::Compatible as u8 => Ok(Self::Compatible),
158 x if x == Self::Additive as u8 => Ok(Self::Additive),
159 x if x == Self::DepOnly as u8 => Ok(Self::DepOnly),
160 _ => Err(()),
161 }
162 }
163}
164
165#[derive(Debug, Serialize, Deserialize)]
167pub struct UpgradeCap {
168 pub id: UID,
169 pub package: ID,
170 pub version: u64,
171 pub policy: u8,
172}
173
174#[derive(Debug, Serialize, Deserialize)]
176pub struct UpgradeTicket {
177 pub cap: ID,
178 pub package: ID,
179 pub policy: u8,
180 pub digest: Vec<u8>,
181}
182
183#[derive(Debug, Serialize, Deserialize)]
185pub struct UpgradeReceipt {
186 pub cap: ID,
187 pub package: ID,
188}
189
190impl MovePackage {
191 pub fn new(
194 id: ObjectID,
195 version: SequenceNumber,
196 module_map: BTreeMap<String, Vec<u8>>,
197 max_move_package_size: u64,
198 type_origin_table: Vec<TypeOrigin>,
199 linkage_table: BTreeMap<ObjectID, UpgradeInfo>,
200 ) -> Result<Self, ExecutionError> {
201 let pkg = Self {
202 id,
203 version,
204 module_map,
205 type_origin_table,
206 linkage_table,
207 };
208 let object_size = pkg.size() as u64;
209 if object_size > max_move_package_size {
210 return Err(ExecutionErrorKind::MovePackageTooBig {
211 object_size,
212 max_object_size: max_move_package_size,
213 }
214 .into());
215 }
216 Ok(pkg)
217 }
218
219 pub fn digest(&self, hash_modules: bool) -> [u8; 32] {
220 Self::compute_digest_for_modules_and_deps(
221 self.module_map.values(),
222 self.linkage_table
223 .values()
224 .map(|UpgradeInfo { upgraded_id, .. }| upgraded_id),
225 hash_modules,
226 )
227 }
228
229 pub fn compute_digest_for_modules_and_deps<'a>(
232 modules: impl IntoIterator<Item = &'a Vec<u8>>,
233 object_ids: impl IntoIterator<Item = &'a ObjectID>,
234 hash_modules: bool,
235 ) -> [u8; 32] {
236 let mut module_digests: Vec<[u8; 32]>;
237 let mut components: Vec<&[u8]> = vec![];
238 if !hash_modules {
239 for module in modules {
240 components.push(module.as_ref())
241 }
242 } else {
243 module_digests = vec![];
244 for module in modules {
245 let mut digest = DefaultHash::default();
246 digest.update(module);
247 module_digests.push(digest.finalize().digest);
248 }
249 components.extend(module_digests.iter().map(|d| d.as_ref()))
250 }
251
252 components.extend(object_ids.into_iter().map(|o| o.as_ref()));
253 components.sort();
255
256 let mut digest = DefaultHash::default();
257 for c in components {
258 digest.update(c);
259 }
260 digest.finalize().digest
261 }
262
263 pub fn new_initial<'p>(
266 modules: &[CompiledModule],
267 protocol_config: &ProtocolConfig,
268 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
269 ) -> Result<Self, ExecutionError> {
270 let module = modules
271 .first()
272 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
273 let runtime_id = ObjectID::from(*module.address());
274 let storage_id = runtime_id;
275 let type_origin_table = build_initial_type_origin_table(modules);
276 Self::from_module_iter_with_type_origin_table(
277 storage_id,
278 runtime_id,
279 OBJECT_START_VERSION,
280 modules,
281 protocol_config,
282 type_origin_table,
283 transitive_dependencies,
284 )
285 }
286
287 pub fn new_upgraded<'p>(
290 &self,
291 storage_id: ObjectID,
292 modules: &[CompiledModule],
293 protocol_config: &ProtocolConfig,
294 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
295 ) -> Result<Self, ExecutionError> {
296 let module = modules
297 .first()
298 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
299 let runtime_id = ObjectID::from(*module.address());
300 let type_origin_table =
301 build_upgraded_type_origin_table(self, modules, storage_id, protocol_config)?;
302 let mut new_version = self.version();
303 new_version.increment();
304 Self::from_module_iter_with_type_origin_table(
305 storage_id,
306 runtime_id,
307 new_version,
308 modules,
309 protocol_config,
310 type_origin_table,
311 transitive_dependencies,
312 )
313 }
314
315 pub fn new_system(
316 version: SequenceNumber,
317 modules: &[CompiledModule],
318 dependencies: impl IntoIterator<Item = ObjectID>,
319 ) -> Self {
320 let module = modules
321 .first()
322 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
323
324 let storage_id = ObjectID::from(*module.address());
325 let type_origin_table = build_initial_type_origin_table(modules);
326
327 let linkage_table = BTreeMap::from_iter(dependencies.into_iter().map(|dep| {
328 let info = UpgradeInfo {
329 upgraded_id: dep,
330 upgraded_version: SequenceNumber::new(),
342 };
343 (dep, info)
344 }));
345
346 let mut module_map = BTreeMap::new();
347 for module in modules.iter() {
348 let name = module.name().to_string();
349 let mut bytes = Vec::new();
350 module
351 .serialize_with_version(module.version, &mut bytes)
352 .unwrap();
353 if module_map.insert(name, bytes).is_some() {
354 panic!(
355 "Duplicate module {} in system package {}",
356 module.self_id(),
357 storage_id
358 );
359 }
360 }
361
362 Self::new(
363 storage_id,
364 version,
365 module_map,
366 u64::MAX, type_origin_table,
368 linkage_table,
369 )
370 .expect("System packages are not subject to a size limit")
371 }
372
373 fn from_module_iter_with_type_origin_table<'p>(
374 storage_id: ObjectID,
375 self_id: ObjectID,
376 version: SequenceNumber,
377 modules: &[CompiledModule],
378 protocol_config: &ProtocolConfig,
379 type_origin_table: Vec<TypeOrigin>,
380 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
381 ) -> Result<Self, ExecutionError> {
382 let mut module_map = BTreeMap::new();
383 let mut immediate_dependencies = BTreeSet::new();
384
385 for module in modules {
386 let name = module.name().to_string();
387
388 immediate_dependencies.extend(
389 module
390 .immediate_dependencies()
391 .into_iter()
392 .map(|dep| ObjectID::from(*dep.address())),
393 );
394
395 let mut bytes = Vec::new();
396 let version = if protocol_config.move_binary_format_version() > VERSION_6 {
397 module.version
398 } else {
399 VERSION_6
400 };
401 module.serialize_with_version(version, &mut bytes).unwrap();
402 let prev = module_map.insert(name, bytes);
403 if protocol_config.new_vm_enabled() && prev.is_some() {
404 return Err(ExecutionError::new_with_source(
405 ExecutionErrorKind::VMVerificationOrDeserializationError,
406 format!(
407 "Duplicate module {} in package {}",
408 module.self_id(),
409 storage_id
410 ),
411 ));
412 }
413 }
414
415 immediate_dependencies.remove(&self_id);
416 let linkage_table = build_linkage_table(
417 immediate_dependencies,
418 transitive_dependencies,
419 protocol_config,
420 )?;
421 Self::new(
422 storage_id,
423 version,
424 module_map,
425 protocol_config.max_move_package_size(),
426 type_origin_table,
427 linkage_table,
428 )
429 }
430
431 pub fn get_module(&self, storage_id: &ModuleId) -> Option<&Vec<u8>> {
437 if self.id != ObjectID::from(*storage_id.address()) {
438 None
439 } else {
440 self.module_map.get(&storage_id.name().to_string())
441 }
442 }
443
444 pub fn size(&self) -> usize {
446 let module_map_size = self
447 .module_map
448 .iter()
449 .map(|(name, module)| name.len() + module.len())
450 .sum::<usize>();
451 let type_origin_table_size = self
452 .type_origin_table
453 .iter()
454 .map(
455 |TypeOrigin {
456 module_name,
457 datatype_name: struct_name,
458 ..
459 }| module_name.len() + struct_name.len() + ObjectID::LENGTH,
460 )
461 .sum::<usize>();
462
463 let linkage_table_size = self.linkage_table.len()
464 * (ObjectID::LENGTH + (ObjectID::LENGTH + 8));
465
466 8 + module_map_size + type_origin_table_size + linkage_table_size
467 }
468
469 pub fn id(&self) -> ObjectID {
470 self.id
471 }
472
473 pub fn version(&self) -> SequenceNumber {
474 self.version
475 }
476
477 pub fn decrement_version(&mut self) {
478 self.version.decrement();
479 }
480
481 pub fn increment_version(&mut self) {
482 self.version.increment();
483 }
484
485 pub fn object_size_for_gas_metering(&self) -> usize {
487 self.size()
488 }
489
490 pub fn serialized_module_map(&self) -> &BTreeMap<String, Vec<u8>> {
491 &self.module_map
492 }
493
494 pub fn type_origin_table(&self) -> &Vec<TypeOrigin> {
495 &self.type_origin_table
496 }
497
498 pub fn type_origin_map(&self) -> BTreeMap<(String, String), ObjectID> {
499 self.type_origin_table
500 .iter()
501 .map(
502 |TypeOrigin {
503 module_name,
504 datatype_name: struct_name,
505 package,
506 }| { ((module_name.clone(), struct_name.clone()), *package) },
507 )
508 .collect()
509 }
510
511 pub fn linkage_table(&self) -> &BTreeMap<ObjectID, UpgradeInfo> {
512 &self.linkage_table
513 }
514
515 pub fn move_linkage_context(&self) -> BTreeMap<AccountAddress, AccountAddress> {
516 self.linkage_table
517 .iter()
518 .map(|(k, v)| ((*k).into(), v.upgraded_id.into()))
519 .collect()
520 }
521
522 pub fn original_package_id(&self) -> ObjectID {
525 if self.version == OBJECT_START_VERSION {
526 return self.id;
528 }
529 let bytes = self.module_map.values().next().expect("Empty module map");
530 let module = CompiledModule::deserialize_with_defaults(bytes)
531 .expect("A Move package contains a module that cannot be deserialized");
532 (*module.address()).into()
533 }
534
535 pub fn deserialize_module(
536 &self,
537 module: &Identifier,
538 binary_config: &BinaryConfig,
539 ) -> SuiResult<CompiledModule> {
540 self.deserialize_module_by_str(module.as_str(), binary_config)
541 }
542
543 pub fn deserialize_module_by_str(
544 &self,
545 module: &str,
546 binary_config: &BinaryConfig,
547 ) -> SuiResult<CompiledModule> {
548 let bytes = self.serialized_module_map().get(module).ok_or_else(|| {
550 SuiErrorKind::ModuleNotFound {
551 module_name: module.to_string(),
552 }
553 })?;
554 CompiledModule::deserialize_with_config(bytes, binary_config).map_err(|error| {
555 SuiErrorKind::ModuleDeserializationFailure {
556 error: error.to_string(),
557 }
558 .into()
559 })
560 }
561
562 pub fn normalize<S: Hash + Eq + Clone + ToString, Pool: normalized::StringPool<String = S>>(
565 &self,
566 pool: &mut Pool,
567 binary_config: &BinaryConfig,
568 include_code: bool,
569 ) -> SuiResult<BTreeMap<String, normalized::Module<S>>> {
570 normalize_modules(pool, self.module_map.values(), binary_config, include_code)
571 }
572
573 pub fn into_serialized_move_package(&self) -> SuiResult<SerializedPackage> {
574 macro_rules! expect_valid_identifier {
575 ($ident_str:expr) => {
576 Identifier::new($ident_str.clone()).map_err(|e| {
577 debug_assert!(
578 false,
579 "Published modules must always have valid identifiers {}",
580 e
581 );
582 SuiErrorKind::ExecutionInvariantViolation
583 })
584 };
585 }
586 let type_origin_table = self
587 .type_origin_table
588 .iter()
589 .map(|ty_origin| {
590 Ok((
591 IntraPackageName {
592 module_name: expect_valid_identifier!(ty_origin.module_name)?,
593 type_name: expect_valid_identifier!(ty_origin.datatype_name)?,
594 },
595 ty_origin.package.into(),
596 ))
597 })
598 .collect::<SuiResult<_>>()?;
599 Ok(SerializedPackage {
600 modules: self
601 .serialized_module_map()
602 .iter()
603 .map(|(k, v)| Ok((expect_valid_identifier!(k)?, v.clone())))
604 .collect::<SuiResult<_>>()?,
605 version_id: self.id.into(),
606 original_id: self.original_package_id().into(),
607 linkage_table: self
608 .linkage_table()
609 .iter()
610 .map(|(k, v)| ((*k).into(), v.upgraded_id.into()))
611 .chain(std::iter::once((
612 self.original_package_id().into(),
613 self.id.into(),
614 )))
615 .collect(),
616 type_origin_table,
617 version: self.version().value(),
618 })
619 }
620}
621
622impl UpgradeCap {
623 pub fn type_() -> StructTag {
624 StructTag {
625 address: SUI_FRAMEWORK_ADDRESS,
626 module: PACKAGE_MODULE_NAME.to_owned(),
627 name: UPGRADECAP_STRUCT_NAME.to_owned(),
628 type_params: vec![],
629 }
630 }
631
632 pub fn new(uid: ObjectID, package_id: ObjectID) -> Self {
635 UpgradeCap {
636 id: UID::new(uid),
637 package: ID::new(package_id),
638 version: 1,
639 policy: UpgradePolicy::COMPATIBLE,
640 }
641 }
642}
643
644impl UpgradeTicket {
645 pub fn type_() -> StructTag {
646 StructTag {
647 address: SUI_FRAMEWORK_ADDRESS,
648 module: PACKAGE_MODULE_NAME.to_owned(),
649 name: UPGRADETICKET_STRUCT_NAME.to_owned(),
650 type_params: vec![],
651 }
652 }
653}
654
655impl UpgradeReceipt {
656 pub fn type_() -> StructTag {
657 StructTag {
658 address: SUI_FRAMEWORK_ADDRESS,
659 module: PACKAGE_MODULE_NAME.to_owned(),
660 name: UPGRADERECEIPT_STRUCT_NAME.to_owned(),
661 type_params: vec![],
662 }
663 }
664
665 pub fn new(upgrade_ticket: UpgradeTicket, upgraded_package_id: ObjectID) -> Self {
668 UpgradeReceipt {
669 cap: upgrade_ticket.cap,
670 package: ID::new(upgraded_package_id),
671 }
672 }
673}
674
675pub fn is_test_fun(name: &IdentStr, module: &CompiledModule, fn_info_map: &FnInfoMap) -> bool {
677 let fn_name = name.to_string();
678 let mod_handle = module.self_handle();
679 let mod_addr = *module.address_identifier_at(mod_handle.address);
680 let fn_info_key = FnInfoKey { fn_name, mod_addr };
681 match fn_info_map.get(&fn_info_key) {
682 Some(fn_info) => fn_info.is_test,
683 None => false,
684 }
685}
686
687pub fn normalize_modules<
690 'a,
691 S: Hash + Eq + Clone + ToString,
692 Pool: normalized::StringPool<String = S>,
693 I,
694>(
695 pool: &mut Pool,
696 modules: I,
697 binary_config: &BinaryConfig,
698 include_code: bool,
699) -> SuiResult<BTreeMap<String, normalized::Module<S>>>
700where
701 I: Iterator<Item = &'a Vec<u8>>,
702{
703 let mut normalized_modules = BTreeMap::new();
704 for bytecode in modules {
705 let module =
706 CompiledModule::deserialize_with_config(bytecode, binary_config).map_err(|error| {
707 SuiErrorKind::ModuleDeserializationFailure {
708 error: error.to_string(),
709 }
710 })?;
711 let normalized_module = normalized::Module::new(pool, &module, include_code);
712 normalized_modules.insert(normalized_module.name().to_string(), normalized_module);
713 }
714 Ok(normalized_modules)
715}
716
717pub fn normalize_deserialized_modules<
720 'a,
721 S: Hash + Eq + Clone + ToString,
722 Pool: normalized::StringPool<String = S>,
723 I,
724>(
725 pool: &mut Pool,
726 modules: I,
727 include_code: bool,
728) -> BTreeMap<String, normalized::Module<S>>
729where
730 I: Iterator<Item = &'a CompiledModule>,
731{
732 let mut normalized_modules = BTreeMap::new();
733 for module in modules {
734 let normalized_module = normalized::Module::new(pool, module, include_code);
735 normalized_modules.insert(normalized_module.name().to_string(), normalized_module);
736 }
737 normalized_modules
738}
739
740fn build_linkage_table<'p>(
741 mut immediate_dependencies: BTreeSet<ObjectID>,
742 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
743 protocol_config: &ProtocolConfig,
744) -> Result<BTreeMap<ObjectID, UpgradeInfo>, ExecutionError> {
745 let mut linkage_table = BTreeMap::new();
746 let mut dep_linkage_tables = vec![];
747
748 for transitive_dep in transitive_dependencies.into_iter() {
749 let original_id = transitive_dep.original_package_id();
753
754 let imm_dep = immediate_dependencies.remove(&original_id);
755
756 if protocol_config.dependency_linkage_error() {
757 dep_linkage_tables.push(&transitive_dep.linkage_table);
758 let existing = linkage_table.insert(
759 original_id,
760 UpgradeInfo {
761 upgraded_id: transitive_dep.id,
762 upgraded_version: transitive_dep.version,
763 },
764 );
765
766 if existing.is_some() {
767 return Err(ExecutionErrorKind::InvalidLinkage.into());
768 }
769 } else {
770 if imm_dep {
771 dep_linkage_tables.push(&transitive_dep.linkage_table);
774 }
775 linkage_table.insert(
776 original_id,
777 UpgradeInfo {
778 upgraded_id: transitive_dep.id,
779 upgraded_version: transitive_dep.version,
780 },
781 );
782 }
783 }
784 if !immediate_dependencies.is_empty() {
786 return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into());
787 }
788
789 for dep_linkage_table in dep_linkage_tables {
791 for (original_id, dep_info) in dep_linkage_table {
792 let Some(our_info) = linkage_table.get(original_id) else {
793 return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into());
794 };
795
796 if our_info.upgraded_version < dep_info.upgraded_version {
797 return Err(ExecutionErrorKind::PublishUpgradeDependencyDowngrade.into());
798 }
799 }
800 }
801
802 Ok(linkage_table)
803}
804
805fn build_initial_type_origin_table(modules: &[CompiledModule]) -> Vec<TypeOrigin> {
806 modules
807 .iter()
808 .flat_map(|m| {
809 m.struct_defs()
810 .iter()
811 .map(|struct_def| {
812 let struct_handle = m.datatype_handle_at(struct_def.struct_handle);
813 let module_name = m.name().to_string();
814 let struct_name = m.identifier_at(struct_handle.name).to_string();
815 let package: ObjectID = (*m.self_id().address()).into();
816 TypeOrigin {
817 module_name,
818 datatype_name: struct_name,
819 package,
820 }
821 })
822 .chain(m.enum_defs().iter().map(|enum_def| {
823 let enum_handle = m.datatype_handle_at(enum_def.enum_handle);
824 let module_name = m.name().to_string();
825 let enum_name = m.identifier_at(enum_handle.name).to_string();
826 let package: ObjectID = (*m.self_id().address()).into();
827 TypeOrigin {
828 module_name,
829 datatype_name: enum_name,
830 package,
831 }
832 }))
833 })
834 .collect()
835}
836
837fn build_upgraded_type_origin_table(
838 predecessor: &MovePackage,
839 modules: &[CompiledModule],
840 storage_id: ObjectID,
841 protocol_config: &ProtocolConfig,
842) -> Result<Vec<TypeOrigin>, ExecutionError> {
843 let mut new_table = vec![];
844 let mut existing_table = predecessor.type_origin_map();
845 for m in modules {
846 for struct_def in m.struct_defs() {
847 let struct_handle = m.datatype_handle_at(struct_def.struct_handle);
848 let module_name = m.name().to_string();
849 let struct_name = m.identifier_at(struct_handle.name).to_string();
850 let mod_key = (module_name.clone(), struct_name.clone());
851 let package = existing_table.remove(&mod_key).unwrap_or(storage_id);
854 new_table.push(TypeOrigin {
855 module_name,
856 datatype_name: struct_name,
857 package,
858 });
859 }
860
861 for enum_def in m.enum_defs() {
862 let enum_handle = m.datatype_handle_at(enum_def.enum_handle);
863 let module_name = m.name().to_string();
864 let enum_name = m.identifier_at(enum_handle.name).to_string();
865 let mod_key = (module_name.clone(), enum_name.clone());
866 let package = existing_table.remove(&mod_key).unwrap_or(storage_id);
869 new_table.push(TypeOrigin {
870 module_name,
871 datatype_name: enum_name,
872 package,
873 });
874 }
875 }
876
877 if !existing_table.is_empty() {
878 if protocol_config.missing_type_is_compatibility_error() {
879 Err(ExecutionError::from_kind(
880 ExecutionErrorKind::PackageUpgradeError {
881 upgrade_error: PackageUpgradeError::IncompatibleUpgrade,
882 },
883 ))
884 } else {
885 Err(ExecutionError::invariant_violation(
886 "Package upgrade missing type from previous version.",
887 ))
888 }
889 } else {
890 Ok(new_table)
891 }
892}