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