1use std::{
38 collections::{BTreeMap, BTreeSet},
39 hash::Hash,
40};
41
42use derive_more::Display;
43use iota_protocol_config::ProtocolConfig;
44use iota_sdk_types::{
45 Identifier, ObjectId, PackageUpgradeError, StructTag, TypeTag, Version,
46 move_package::{MovePackage, TypeOrigin, UpgradeInfo},
47};
48use move_binary_format::{
49 binary_config::BinaryConfig,
50 file_format::CompiledModule,
51 file_format_common::{IOTA_METADATA_KEY, VERSION_6},
52 normalized,
53};
54use move_core_types::identifier::IdentStr;
55use serde::{Deserialize, Serialize};
56use serde_with::{Bytes, serde_as};
57
58use crate::{
59 Address,
60 collection_types::{Entry, VecMap},
61 derived_object,
62 error::{ExecutionError, ExecutionErrorKind, IotaError, IotaResult},
63 id::{ID, UID},
64 iota_sdk_types_conversions::identifier_core_to_sdk,
65 iota_serde::TypeName,
66};
67
68pub const PACKAGE_METADATA_MODULE_NAME: Identifier = Identifier::from_static("package_metadata");
69pub const PACKAGE_METADATA_V1_STRUCT_NAME: Identifier =
70 Identifier::from_static("PackageMetadataV1");
71pub const PACKAGE_METADATA_KEY_STRUCT_NAME: Identifier =
72 Identifier::from_static("PackageMetadataKey");
73
74#[derive(Clone, Debug)]
75pub struct FnInfo {
77 pub is_test: bool,
80 pub authenticator_version: Option<u8>,
83 pub is_view: bool,
84}
85
86#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
87pub struct FnInfoKey {
89 pub fn_name: String,
90 pub mod_name: String,
91 pub mod_addr: Address,
92}
93
94pub type FnInfoMap = BTreeMap<FnInfoKey, FnInfo>;
96
97#[repr(u8)]
102#[derive(Display, Debug, Clone, Copy)]
103pub enum UpgradePolicy {
104 #[display("COMPATIBLE")]
105 Compatible = 0,
106 #[display("ADDITIVE")]
107 Additive = 128,
108 #[display("DEP_ONLY")]
109 DepOnly = 192,
110}
111
112impl UpgradePolicy {
113 pub const COMPATIBLE: u8 = Self::Compatible as u8;
115 pub const ADDITIVE: u8 = Self::Additive as u8;
116 pub const DEP_ONLY: u8 = Self::DepOnly as u8;
117
118 pub fn is_valid_policy(policy: &u8) -> bool {
119 Self::try_from(*policy).is_ok()
120 }
121}
122
123impl TryFrom<u8> for UpgradePolicy {
124 type Error = ();
125 fn try_from(value: u8) -> Result<Self, Self::Error> {
126 match value {
127 x if x == Self::Compatible as u8 => Ok(Self::Compatible),
128 x if x == Self::Additive as u8 => Ok(Self::Additive),
129 x if x == Self::DepOnly as u8 => Ok(Self::DepOnly),
130 _ => Err(()),
131 }
132 }
133}
134
135#[derive(Debug, Serialize, Deserialize)]
137pub struct UpgradeCap {
138 pub id: UID,
139 pub package: ID,
140 pub version: u64,
141 pub policy: u8,
142}
143
144#[derive(Debug, Serialize, Deserialize)]
146pub struct UpgradeTicket {
147 pub cap: ID,
148 pub package: ID,
149 pub policy: u8,
150 pub digest: Vec<u8>,
151}
152
153#[derive(Debug, Serialize, Deserialize)]
155pub struct UpgradeReceipt {
156 pub cap: ID,
157 pub package: ID,
158}
159
160mod move_package_ext {
161 pub trait Sealed {}
162 impl Sealed for super::MovePackage {}
163}
164
165pub trait MovePackageExt: Sized + move_package_ext::Sealed {
166 fn new_initial<'p>(
167 modules: &[CompiledModule],
168 protocol_config: &ProtocolConfig,
169 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
170 ) -> Result<MovePackage, ExecutionError>;
171
172 fn new_upgraded<'p>(
173 &self,
174 storage_id: ObjectId,
175 modules: &[CompiledModule],
176 protocol_config: &ProtocolConfig,
177 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
178 ) -> Result<MovePackage, ExecutionError>;
179
180 fn new_system(
181 version: Version,
182 modules: &[CompiledModule],
183 dependencies: impl IntoIterator<Item = ObjectId>,
184 ) -> MovePackage;
185
186 fn from_module_iter_with_type_origin_table<'p>(
187 storage_id: ObjectId,
188 self_id: ObjectId,
189 version: Version,
190 modules: &[CompiledModule],
191 protocol_config: &ProtocolConfig,
192 type_origin_table: Vec<TypeOrigin>,
193 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
194 ) -> Result<MovePackage, ExecutionError>;
195
196 fn original_package_id(&self) -> ObjectId;
197
198 fn deserialize_module(
199 &self,
200 module: &Identifier,
201 binary_config: &BinaryConfig,
202 ) -> IotaResult<CompiledModule>;
203
204 fn normalize<S: Hash + Eq + Clone + ToString, Pool: normalized::StringPool<String = S>>(
205 &self,
206 pool: &mut Pool,
207 binary_config: &BinaryConfig,
208 include_code: bool,
209 ) -> IotaResult<BTreeMap<String, normalized::Module<S>>>;
210}
211
212impl MovePackageExt for MovePackage {
213 fn new_initial<'p>(
221 modules: &[CompiledModule],
222 protocol_config: &ProtocolConfig,
223 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
224 ) -> Result<MovePackage, ExecutionError> {
225 let module = modules
226 .first()
227 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
228 let runtime_id = ObjectId::new(module.address().into_bytes());
229 let storage_id = runtime_id;
230 let type_origin_table = build_initial_type_origin_table(modules);
231
232 MovePackage::from_module_iter_with_type_origin_table(
233 storage_id,
234 runtime_id,
235 Version::OBJECT_START,
236 modules,
237 protocol_config,
238 type_origin_table,
239 transitive_dependencies,
240 )
241 }
242
243 fn new_upgraded<'p>(
251 &self,
252 storage_id: ObjectId,
253 modules: &[CompiledModule],
254 protocol_config: &ProtocolConfig,
255 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
256 ) -> Result<MovePackage, ExecutionError> {
257 let module = modules
258 .first()
259 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
260 let runtime_id = ObjectId::new(module.address().into_bytes());
261 let type_origin_table = build_upgraded_type_origin_table(self, modules, storage_id)?;
262 let mut new_version = self.version();
263 new_version.increment().unwrap();
264
265 MovePackage::from_module_iter_with_type_origin_table(
266 storage_id,
267 runtime_id,
268 new_version,
269 modules,
270 protocol_config,
271 type_origin_table,
272 transitive_dependencies,
273 )
274 }
275
276 fn new_system(
277 version: Version,
278 modules: &[CompiledModule],
279 dependencies: impl IntoIterator<Item = ObjectId>,
280 ) -> MovePackage {
281 let module = modules
282 .first()
283 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
284
285 let storage_id = ObjectId::new(module.address().into_bytes());
286 let type_origin_table = build_initial_type_origin_table(modules);
287
288 let linkage_table = BTreeMap::from_iter(dependencies.into_iter().map(|dep| {
289 let info = UpgradeInfo {
290 upgraded_id: dep,
291 upgraded_version: Version::default(),
303 };
304 (dep, info)
305 }));
306
307 let module_map = BTreeMap::from_iter(modules.iter().map(|module| {
308 let name = identifier_core_to_sdk(module.name());
309 let mut bytes = Vec::new();
310 module
311 .serialize_with_version(module.version, &mut bytes)
312 .unwrap();
313 (name, bytes)
314 }));
315
316 MovePackage::new(
317 storage_id,
318 version,
319 module_map,
320 u64::MAX, type_origin_table,
322 linkage_table,
323 )
324 .expect("System packages are not subject to a size limit")
325 }
326
327 fn from_module_iter_with_type_origin_table<'p>(
328 storage_id: ObjectId,
329 self_id: ObjectId,
330 version: Version,
331 modules: &[CompiledModule],
332 protocol_config: &ProtocolConfig,
333 type_origin_table: Vec<TypeOrigin>,
334 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
335 ) -> Result<MovePackage, ExecutionError> {
336 let mut module_map = BTreeMap::new();
337 let mut immediate_dependencies = BTreeSet::new();
338
339 for module in modules {
340 let name = identifier_core_to_sdk(module.name());
341
342 immediate_dependencies.extend(
343 module
344 .immediate_dependencies()
345 .into_iter()
346 .map(|dep| ObjectId::new(dep.address().into_bytes())),
347 );
348
349 let mut bytes = Vec::new();
350 let version = if protocol_config.move_binary_format_version() > VERSION_6 {
351 module.version
352 } else {
353 VERSION_6
354 };
355 module.serialize_with_version(version, &mut bytes).unwrap();
356 module_map.insert(name, bytes);
357 }
358
359 immediate_dependencies.remove(&self_id);
360 let linkage_table = build_linkage_table(
361 immediate_dependencies,
362 transitive_dependencies,
363 protocol_config,
364 )?;
365
366 Ok(MovePackage::new(
367 storage_id,
368 version,
369 module_map,
370 protocol_config.max_move_package_size(),
371 type_origin_table,
372 linkage_table,
373 )?)
374 }
375
376 fn original_package_id(&self) -> ObjectId {
384 if self.version == Version::OBJECT_START {
385 return self.id;
387 }
388
389 let bytes = self.modules.values().next().expect("Empty module map");
390 let module = CompiledModule::deserialize_with_defaults(bytes)
394 .expect("A Move package contains a module that cannot be deserialized");
395 ObjectId::new(module.address().into_bytes())
396 }
397
398 fn deserialize_module(
399 &self,
400 module: &Identifier,
401 binary_config: &BinaryConfig,
402 ) -> IotaResult<CompiledModule> {
403 let bytes =
405 self.serialized_module_map()
406 .get(module)
407 .ok_or_else(|| IotaError::ModuleNotFound {
408 module_name: module.to_string(),
409 })?;
410
411 CompiledModule::deserialize_with_config(bytes, binary_config).map_err(|error| {
412 IotaError::ModuleDeserializationFailure {
413 error: error.to_string(),
414 }
415 })
416 }
417
418 fn normalize<S: Hash + Eq + Clone + ToString, Pool: normalized::StringPool<String = S>>(
421 &self,
422 pool: &mut Pool,
423 binary_config: &BinaryConfig,
424 include_code: bool,
425 ) -> IotaResult<BTreeMap<String, normalized::Module<S>>> {
426 normalize_modules(pool, self.modules.values(), binary_config, include_code)
427 }
428}
429
430impl UpgradeCap {
431 pub fn new(uid: ObjectId, package_id: ObjectId) -> Self {
434 UpgradeCap {
435 id: UID::new(uid),
436 package: ID::new(package_id),
437 version: 1,
438 policy: UpgradePolicy::COMPATIBLE,
439 }
440 }
441}
442
443impl UpgradeReceipt {
444 pub fn new(upgrade_ticket: UpgradeTicket, upgraded_package_id: ObjectId) -> Self {
447 UpgradeReceipt {
448 cap: upgrade_ticket.cap,
449 package: ID::new(upgraded_package_id),
450 }
451 }
452}
453
454pub fn is_test_fun(name: &str, module: &CompiledModule, fn_info_map: &FnInfoMap) -> bool {
456 let mod_handle = module.self_handle();
457 let mod_addr = Address::new(
458 module
459 .address_identifier_at(mod_handle.address)
460 .into_bytes(),
461 );
462 let mod_name = module.name().to_string();
463 let fn_info_key = FnInfoKey {
464 fn_name: name.to_string(),
465 mod_name,
466 mod_addr,
467 };
468 match fn_info_map.get(&fn_info_key) {
469 Some(fn_info) => fn_info.is_test,
470 None => false,
471 }
472}
473
474pub fn get_authenticator_version_from_fun(
475 name: &str,
476 module: &CompiledModule,
477 fn_info_map: &FnInfoMap,
478) -> Option<u8> {
479 let mod_handle = module.self_handle();
480 let mod_addr = Address::from(
481 module
482 .address_identifier_at(mod_handle.address)
483 .into_bytes(),
484 );
485 let mod_name = module.name().to_string();
486 let fn_info_key = FnInfoKey {
487 fn_name: name.to_string(),
488 mod_name,
489 mod_addr,
490 };
491 match fn_info_map.get(&fn_info_key) {
492 Some(FnInfo {
493 is_test: _,
494 authenticator_version: Some(v),
495 is_view: _,
496 }) => Some(*v),
497 _ => None,
498 }
499}
500
501pub fn is_view_function_from_fn_info(
503 name: &IdentStr,
504 module: &CompiledModule,
505 fn_info_map: &FnInfoMap,
506) -> bool {
507 let fn_name = name.to_string();
508 let mod_handle = module.self_handle();
509 let mod_addr = Address::from(
510 module
511 .address_identifier_at(mod_handle.address)
512 .into_bytes(),
513 );
514 let mod_name = module.name().to_string();
515 let fn_info_key = FnInfoKey {
516 fn_name,
517 mod_name,
518 mod_addr,
519 };
520 fn_info_map
521 .get(&fn_info_key)
522 .map(|info| info.is_view)
523 .unwrap_or(false)
524}
525
526pub fn normalize_modules<
529 'a,
530 S: Hash + Eq + Clone + ToString,
531 Pool: normalized::StringPool<String = S>,
532 I,
533>(
534 pool: &mut Pool,
535 modules: I,
536 binary_config: &BinaryConfig,
537 include_code: bool,
538) -> IotaResult<BTreeMap<String, normalized::Module<S>>>
539where
540 I: Iterator<Item = &'a Vec<u8>>,
541{
542 let mut normalized_modules = BTreeMap::new();
543 for bytecode in modules {
544 let module =
545 CompiledModule::deserialize_with_config(bytecode, binary_config).map_err(|error| {
546 IotaError::ModuleDeserializationFailure {
547 error: error.to_string(),
548 }
549 })?;
550 let normalized_module = normalized::Module::new(pool, &module, include_code);
551 normalized_modules.insert(normalized_module.name().to_string(), normalized_module);
552 }
553 Ok(normalized_modules)
554}
555
556pub fn normalize_modules_with_metadata<
562 'a,
563 S: Hash + Eq + Clone + ToString,
564 Pool: normalized::StringPool<String = S>,
565 I,
566>(
567 pool: &mut Pool,
568 modules: I,
569 binary_config: &BinaryConfig,
570 include_code: bool,
571 protocol_config: Option<&ProtocolConfig>,
572) -> IotaResult<BTreeMap<String, (normalized::Module<S>, RuntimeModuleMetadata)>>
573where
574 I: Iterator<Item = &'a Vec<u8>>,
575{
576 let mut normalized_modules = BTreeMap::new();
577 for bytecode in modules {
578 let module =
579 CompiledModule::deserialize_with_config(bytecode, binary_config).map_err(|error| {
580 IotaError::ModuleDeserializationFailure {
581 error: error.to_string(),
582 }
583 })?;
584 let metadata = runtime_module_metadata(&module, protocol_config)?;
585 let normalized_module = normalized::Module::new(pool, &module, include_code);
586 normalized_modules.insert(
587 normalized_module.name().to_string(),
588 (normalized_module, metadata),
589 );
590 }
591 Ok(normalized_modules)
592}
593
594pub fn normalize_deserialized_modules<
597 'a,
598 S: Hash + Eq + Clone + ToString,
599 Pool: normalized::StringPool<String = S>,
600 I,
601>(
602 pool: &mut Pool,
603 modules: I,
604 include_code: bool,
605) -> BTreeMap<String, normalized::Module<S>>
606where
607 I: Iterator<Item = &'a CompiledModule>,
608{
609 let mut normalized_modules = BTreeMap::new();
610 for module in modules {
611 let normalized_module = normalized::Module::new(pool, module, include_code);
612 normalized_modules.insert(normalized_module.name().to_string(), normalized_module);
613 }
614 normalized_modules
615}
616
617pub fn normalize_deserialized_modules_with_metadata<
623 'a,
624 S: Hash + Eq + Clone + ToString,
625 Pool: normalized::StringPool<String = S>,
626 I,
627>(
628 pool: &mut Pool,
629 modules: I,
630 include_code: bool,
631 protocol_config: Option<&ProtocolConfig>,
632) -> IotaResult<BTreeMap<String, (normalized::Module<S>, RuntimeModuleMetadata)>>
633where
634 I: Iterator<Item = &'a CompiledModule>,
635{
636 let mut normalized_modules = BTreeMap::new();
637 for module in modules {
638 let metadata = runtime_module_metadata(module, protocol_config)?;
639 let normalized_module = normalized::Module::new(pool, module, include_code);
640 normalized_modules.insert(
641 normalized_module.name().to_string(),
642 (normalized_module, metadata),
643 );
644 }
645 Ok(normalized_modules)
646}
647
648fn runtime_module_metadata(
649 module: &CompiledModule,
650 protocol_config: Option<&ProtocolConfig>,
651) -> IotaResult<RuntimeModuleMetadata> {
652 let build_config = ProtocolBuildConfig::from(protocol_config);
653 let Some(metadata) = module
654 .metadata
655 .iter()
656 .find(|metadata| metadata.key == IOTA_METADATA_KEY)
657 else {
658 if build_config.allow_view_function {
659 return Ok(RuntimeModuleMetadata::v2());
660 } else {
661 return Ok(RuntimeModuleMetadata::v1());
662 }
663 };
664
665 let metadata_wrapper: RuntimeModuleMetadataWrapper =
666 bcs::from_bytes(&metadata.value).map_err(|error| {
667 IotaError::RuntimeModuleMetadataDeserialization {
668 error: error.to_string(),
669 }
670 })?;
671 metadata_wrapper.try_into_runtime_module_metadata(&build_config)
672}
673
674fn build_linkage_table<'p>(
675 mut immediate_dependencies: BTreeSet<ObjectId>,
676 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
677 protocol_config: &ProtocolConfig,
678) -> Result<BTreeMap<ObjectId, UpgradeInfo>, ExecutionError> {
679 let mut linkage_table = BTreeMap::new();
680 let mut dep_linkage_tables = vec![];
681
682 for transitive_dep in transitive_dependencies.into_iter() {
683 let original_id = MovePackage::original_package_id(transitive_dep);
687
688 let imm_dep = immediate_dependencies.remove(&original_id);
689
690 if protocol_config.dependency_linkage_error() {
691 dep_linkage_tables.push(&transitive_dep.linkage_table);
692
693 let existing = linkage_table.insert(
694 original_id,
695 UpgradeInfo {
696 upgraded_id: transitive_dep.id,
697 upgraded_version: transitive_dep.version,
698 },
699 );
700
701 if existing.is_some() {
702 return Err(ExecutionErrorKind::InvalidLinkage.into());
703 }
704 } else {
705 if imm_dep {
706 dep_linkage_tables.push(&transitive_dep.linkage_table);
709 }
710 linkage_table.insert(
711 original_id,
712 UpgradeInfo {
713 upgraded_id: transitive_dep.id,
714 upgraded_version: transitive_dep.version,
715 },
716 );
717 }
718 }
719 if !immediate_dependencies.is_empty() {
721 return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into());
722 }
723
724 for dep_linkage_table in dep_linkage_tables {
726 for (original_id, dep_info) in dep_linkage_table {
727 let Some(our_info) = linkage_table.get(original_id) else {
728 return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into());
729 };
730
731 if our_info.upgraded_version < dep_info.upgraded_version {
732 return Err(ExecutionErrorKind::PublishUpgradeDependencyDowngrade.into());
733 }
734 }
735 }
736
737 Ok(linkage_table)
738}
739
740fn build_initial_type_origin_table(modules: &[CompiledModule]) -> Vec<TypeOrigin> {
741 modules
742 .iter()
743 .flat_map(|m| {
744 m.struct_defs()
745 .iter()
746 .map(|struct_def| {
747 let struct_handle = m.datatype_handle_at(struct_def.struct_handle);
748 let package = ObjectId::new(m.self_id().address().into_bytes());
749 TypeOrigin {
750 module_name: identifier_core_to_sdk(m.name()),
751 datatype_name: identifier_core_to_sdk(m.identifier_at(struct_handle.name)),
752 package,
753 }
754 })
755 .chain(m.enum_defs().iter().map(|enum_def| {
756 let enum_handle = m.datatype_handle_at(enum_def.enum_handle);
757 let package = ObjectId::new(m.self_id().address().into_bytes());
758 TypeOrigin {
759 module_name: identifier_core_to_sdk(m.name()),
760 datatype_name: identifier_core_to_sdk(m.identifier_at(enum_handle.name)),
761 package,
762 }
763 }))
764 })
765 .collect()
766}
767
768fn build_upgraded_type_origin_table(
769 predecessor: &MovePackage,
770 modules: &[CompiledModule],
771 storage_id: ObjectId,
772) -> Result<Vec<TypeOrigin>, ExecutionError> {
773 let mut new_table = vec![];
774 let mut existing_table = predecessor.type_origin_map();
775 for m in modules {
776 for struct_def in m.struct_defs() {
777 let struct_handle = m.datatype_handle_at(struct_def.struct_handle);
778 let module_name = identifier_core_to_sdk(m.name());
779 let struct_name = identifier_core_to_sdk(m.identifier_at(struct_handle.name));
780 let mod_key = (module_name.clone(), struct_name.clone());
781 let package = existing_table.remove(&mod_key).unwrap_or(storage_id);
784 new_table.push(TypeOrigin {
785 module_name,
786 datatype_name: struct_name,
787 package,
788 });
789 }
790
791 for enum_def in m.enum_defs() {
792 let enum_handle = m.datatype_handle_at(enum_def.enum_handle);
793 let module_name = identifier_core_to_sdk(m.name());
794 let enum_name = identifier_core_to_sdk(m.identifier_at(enum_handle.name));
795 let mod_key = (module_name.clone(), enum_name.clone());
796 let package = existing_table.remove(&mod_key).unwrap_or(storage_id);
799 new_table.push(TypeOrigin {
800 module_name,
801 datatype_name: enum_name,
802 package,
803 });
804 }
805 }
806
807 if !existing_table.is_empty() {
808 Err(ExecutionError::from_kind(
809 ExecutionErrorKind::PackageUpgradeError {
810 kind: PackageUpgradeError::IncompatibleUpgrade,
811 },
812 ))
813 } else {
814 Ok(new_table)
815 }
816}
817
818#[derive(Debug, Clone, Copy, Default)]
825pub struct ProtocolBuildConfig {
826 pub allow_view_function: bool,
829}
830
831impl ProtocolBuildConfig {
832 pub fn from_protocol_config(protocol_config: &ProtocolConfig) -> Self {
834 Self {
835 allow_view_function: protocol_config.package_metadata_with_dynamic_module_metadata(),
836 }
837 }
838}
839
840impl From<&ProtocolConfig> for ProtocolBuildConfig {
841 fn from(protocol_config: &ProtocolConfig) -> Self {
842 Self::from_protocol_config(protocol_config)
843 }
844}
845
846impl From<Option<&ProtocolConfig>> for ProtocolBuildConfig {
847 fn from(protocol_config: Option<&ProtocolConfig>) -> Self {
848 protocol_config
849 .map(Self::from_protocol_config)
850 .unwrap_or_default()
851 }
852}
853
854#[serde_as]
856#[derive(Debug, Clone, Serialize, Deserialize)]
857pub struct RuntimeModuleMetadataWrapper {
858 pub version: u64,
859 #[serde_as(as = "Bytes")]
860 pub inner: Vec<u8>,
861}
862
863impl RuntimeModuleMetadataWrapper {
864 pub fn to_bcs_bytes(&self) -> Vec<u8> {
865 bcs::to_bytes(&self).unwrap()
867 }
868
869 pub fn try_into_runtime_module_metadata(
870 &self,
871 protocol_build_config: &ProtocolBuildConfig,
872 ) -> Result<RuntimeModuleMetadata, IotaError> {
873 match self.version {
874 1 => {
875 let inner: RuntimeModuleMetadataV1 = bcs::from_bytes(&self.inner).map_err(|e| {
876 IotaError::RuntimeModuleMetadataDeserialization {
877 error: e.to_string(),
878 }
879 })?;
880 Ok(RuntimeModuleMetadata::V1(inner))
881 }
882 2 if protocol_build_config.allow_view_function => {
883 let inner: RuntimeModuleMetadataV2 = bcs::from_bytes(&self.inner).map_err(|e| {
884 IotaError::RuntimeModuleMetadataDeserialization {
885 error: e.to_string(),
886 }
887 })?;
888 Ok(RuntimeModuleMetadata::V2(inner))
889 }
890 _ => Err(IotaError::RuntimeModuleMetadataDeserialization {
891 error: format!(
892 "Unsupported runtime module metadata version: {}",
893 self.version
894 ),
895 }),
896 }
897 }
898}
899
900impl From<RuntimeModuleMetadata> for RuntimeModuleMetadataWrapper {
901 fn from(metadata: RuntimeModuleMetadata) -> Self {
902 match metadata {
903 RuntimeModuleMetadata::V1(inner) => RuntimeModuleMetadataWrapper {
904 version: 1,
905 inner: inner.to_bcs_bytes(),
906 },
907 RuntimeModuleMetadata::V2(inner) => RuntimeModuleMetadataWrapper {
908 version: 2,
909 inner: inner.to_bcs_bytes(),
910 },
911 }
912 }
913}
914
915#[derive(Debug, Clone, Serialize, Deserialize)]
917pub enum RuntimeModuleMetadata {
918 V1(RuntimeModuleMetadataV1),
919 V2(RuntimeModuleMetadataV2),
920}
921
922impl RuntimeModuleMetadata {
923 pub fn v1() -> Self {
924 RuntimeModuleMetadata::V1(RuntimeModuleMetadataV1::default())
925 }
926
927 pub fn v2() -> Self {
928 RuntimeModuleMetadata::V2(RuntimeModuleMetadataV2::default())
929 }
930
931 pub fn add_function_attribute(&mut self, function_name: String, attribute: IotaAttribute) {
942 match (self, attribute) {
943 (RuntimeModuleMetadata::V1(metadata), IotaAttribute::V1(attribute)) => {
944 metadata.add_function_attribute(function_name, attribute)
945 }
946 (RuntimeModuleMetadata::V2(metadata), IotaAttribute::V2(attribute)) => {
947 metadata.add_function_attribute(function_name, attribute)
948 }
949 _ => panic!("attribute version does not match runtime module metadata version"),
950 }
951 }
952
953 pub fn is_empty(&self) -> bool {
954 match self {
955 RuntimeModuleMetadata::V1(metadata) => metadata.is_empty(),
956 RuntimeModuleMetadata::V2(metadata) => metadata.is_empty(),
957 }
958 }
959}
960
961#[derive(Debug, Clone)]
966pub enum IotaAttribute {
967 V1(IotaAttributeV1),
968 V2(IotaAttributeV2),
969}
970
971#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
973pub enum IotaAttributeV1 {
974 Authenticator(AuthenticatorAttribute),
975}
976
977#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
979pub enum IotaAttributeV2 {
980 Authenticator(AuthenticatorAttribute),
981 View,
982}
983
984#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
985pub struct AuthenticatorAttribute {
986 pub version: u8,
987}
988
989impl IotaAttributeV1 {
990 pub fn authenticator_attribute(version: u8) -> Self {
991 IotaAttributeV1::Authenticator(AuthenticatorAttribute { version })
992 }
993}
994
995impl IotaAttributeV2 {
996 pub fn authenticator_attribute(version: u8) -> Self {
997 IotaAttributeV2::Authenticator(AuthenticatorAttribute { version })
998 }
999
1000 pub fn view_attribute() -> Self {
1001 IotaAttributeV2::View
1002 }
1003}
1004
1005#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1007pub struct RuntimeModuleMetadataV1 {
1008 pub fun_attributes: BTreeMap<String, Vec<IotaAttributeV1>>,
1010}
1011
1012#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1014pub struct RuntimeModuleMetadataV2 {
1015 pub fun_attributes: BTreeMap<String, Vec<IotaAttributeV2>>,
1017}
1018
1019impl RuntimeModuleMetadataV1 {
1020 pub fn add_function_attribute(&mut self, function_name: String, attribute: IotaAttributeV1) {
1021 self.fun_attributes
1022 .entry(function_name)
1023 .or_default()
1024 .push(attribute);
1025 }
1026
1027 pub fn is_empty(&self) -> bool {
1028 self.fun_attributes.is_empty()
1029 }
1030
1031 pub fn fun_attributes_iter(&self) -> impl Iterator<Item = (&String, &Vec<IotaAttributeV1>)> {
1032 self.fun_attributes.iter()
1033 }
1034
1035 pub fn to_bcs_bytes(&self) -> Vec<u8> {
1036 bcs::to_bytes(&self).unwrap()
1038 }
1039}
1040
1041impl RuntimeModuleMetadataV2 {
1042 pub fn add_function_attribute(&mut self, function_name: String, attribute: IotaAttributeV2) {
1043 self.fun_attributes
1044 .entry(function_name)
1045 .or_default()
1046 .push(attribute);
1047 }
1048
1049 pub fn is_empty(&self) -> bool {
1050 self.fun_attributes.is_empty()
1051 }
1052 pub fn fun_attributes_iter(&self) -> impl Iterator<Item = (&String, &Vec<IotaAttributeV2>)> {
1053 self.fun_attributes.iter()
1054 }
1055
1056 pub fn to_bcs_bytes(&self) -> Vec<u8> {
1057 bcs::to_bytes(&self).unwrap()
1059 }
1060}
1061
1062#[derive(Debug, Clone, Serialize, Deserialize)]
1067pub enum PackageMetadata {
1068 V1(PackageMetadataV1),
1069}
1070
1071impl PackageMetadata {
1072 pub fn new_v1(
1075 uid: ObjectId,
1076 storage_id: ObjectId,
1077 runtime_id: ObjectId,
1078 package_version: u64,
1079 modules_metadata_map: BTreeMap<String, BTreeMap<String, TypeTag>>,
1080 ) -> Self {
1081 PackageMetadata::V1(PackageMetadataV1::new(
1082 uid,
1083 storage_id,
1084 runtime_id,
1085 package_version,
1086 modules_metadata_map,
1087 ))
1088 }
1089
1090 pub fn type_(&self) -> StructTag {
1091 match self {
1092 PackageMetadata::V1(_) => PackageMetadataV1::type_(),
1093 }
1094 }
1095
1096 pub fn to_bcs_bytes(&self) -> Vec<u8> {
1097 match self {
1098 PackageMetadata::V1(inner) => inner.to_bcs_bytes(),
1099 }
1100 }
1101}
1102
1103#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)]
1104pub struct PackageMetadataKey {
1105 dummy_field: bool,
1109}
1110
1111impl PackageMetadataKey {
1112 pub fn tag() -> StructTag {
1113 StructTag::new(
1114 Address::FRAMEWORK,
1115 PACKAGE_METADATA_MODULE_NAME,
1116 PACKAGE_METADATA_KEY_STRUCT_NAME,
1117 Vec::new(),
1118 )
1119 }
1120
1121 pub fn to_bcs_bytes(&self) -> Vec<u8> {
1122 bcs::to_bytes(&self).unwrap()
1124 }
1125}
1126
1127pub fn derive_package_metadata_id(package_storage_id: ObjectId) -> ObjectId {
1128 derived_object::derive_object_id(
1129 package_storage_id,
1130 &PackageMetadataKey::tag().into(),
1131 &PackageMetadataKey::default().to_bcs_bytes(),
1132 )
1133 .unwrap() }
1135
1136#[derive(Debug, Clone, Serialize, Deserialize)]
1138pub struct PackageMetadataV1 {
1139 pub uid: UID,
1141 pub storage_id: ID,
1145 pub runtime_id: ID,
1148 pub package_version: u64,
1150 pub modules_metadata: VecMap<String, ModuleMetadataV1>,
1152}
1153
1154impl PackageMetadataV1 {
1155 fn new(
1156 uid: ObjectId,
1157 storage_id: ObjectId,
1158 runtime_id: ObjectId,
1159 package_version: u64,
1160 modules_metadata_map: BTreeMap<String, BTreeMap<String, TypeTag>>,
1161 ) -> Self {
1162 let mut modules_metadata = VecMap { contents: vec![] };
1163
1164 for (module_name, module_metadata_map) in modules_metadata_map {
1165 let mut module_metadata = ModuleMetadataV1 {
1166 authenticator_metadata: vec![],
1167 };
1168 for (function_name, account_type) in module_metadata_map {
1169 module_metadata
1170 .authenticator_metadata
1171 .push(AuthenticatorMetadataV1 {
1172 function_name,
1173 account_type,
1174 });
1175 }
1176 modules_metadata.contents.push(Entry {
1177 key: module_name,
1178 value: module_metadata,
1179 });
1180 }
1181
1182 Self {
1183 uid: UID::new(uid),
1184 storage_id: ID::new(storage_id),
1185 runtime_id: ID::new(runtime_id),
1186 package_version,
1187 modules_metadata,
1188 }
1189 }
1190
1191 pub fn type_() -> StructTag {
1192 StructTag::new(
1193 Address::FRAMEWORK,
1194 PACKAGE_METADATA_MODULE_NAME,
1195 PACKAGE_METADATA_V1_STRUCT_NAME,
1196 vec![],
1197 )
1198 }
1199
1200 pub fn to_bcs_bytes(&self) -> Vec<u8> {
1201 bcs::to_bytes(&self).unwrap()
1203 }
1204}
1205
1206#[derive(Debug, Clone, Serialize, Deserialize)]
1208pub struct ModuleMetadataV1 {
1209 pub authenticator_metadata: Vec<AuthenticatorMetadataV1>,
1210}
1211
1212impl ModuleMetadataV1 {
1213 pub fn is_empty(&self) -> bool {
1214 self.authenticator_metadata.is_empty()
1215 }
1216}
1217
1218#[serde_as]
1220#[derive(Debug, Clone, Serialize, Deserialize)]
1221pub struct AuthenticatorMetadataV1 {
1222 pub function_name: String,
1223 #[serde_as(as = "TypeName")]
1224 pub account_type: TypeTag,
1225}