1use std::{
38 collections::{BTreeMap, BTreeSet},
39 hash::Hash,
40};
41
42use derive_more::Display;
43use iota_protocol_config::ProtocolConfig;
44pub use iota_sdk_types::move_package::{MovePackage, TypeOrigin, UpgradeInfo};
45use iota_sdk_types::{Identifier, Version};
46use move_binary_format::{
47 binary_config::BinaryConfig, file_format::CompiledModule, file_format_common::VERSION_6,
48 normalized,
49};
50use serde::{Deserialize, Serialize};
51use serde_with::{Bytes, serde_as};
52
53use crate::{
54 IotaAddress, TypeTag,
55 base_types::{ObjectID, SequenceNumber, StructTag},
56 collection_types::{Entry, VecMap},
57 derived_object,
58 error::{ExecutionError, ExecutionErrorKind, IotaError, IotaResult},
59 execution_status::PackageUpgradeError,
60 id::{ID, UID},
61 iota_serde::TypeName,
62};
63
64pub const PACKAGE_METADATA_MODULE_NAME: Identifier = Identifier::from_static("package_metadata");
65pub const PACKAGE_METADATA_V1_STRUCT_NAME: Identifier =
66 Identifier::from_static("PackageMetadataV1");
67pub const PACKAGE_METADATA_KEY_STRUCT_NAME: Identifier =
68 Identifier::from_static("PackageMetadataKey");
69
70#[derive(Clone, Debug)]
71pub struct FnInfo {
73 pub is_test: bool,
76 pub authenticator_version: Option<u8>,
79}
80
81#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
82pub struct FnInfoKey {
84 pub fn_name: String,
85 pub mod_name: String,
86 pub mod_addr: IotaAddress,
87}
88
89pub type FnInfoMap = BTreeMap<FnInfoKey, FnInfo>;
91
92#[repr(u8)]
97#[derive(Display, Debug, Clone, Copy)]
98pub enum UpgradePolicy {
99 #[display("COMPATIBLE")]
100 Compatible = 0,
101 #[display("ADDITIVE")]
102 Additive = 128,
103 #[display("DEP_ONLY")]
104 DepOnly = 192,
105}
106
107impl UpgradePolicy {
108 pub const COMPATIBLE: u8 = Self::Compatible as u8;
110 pub const ADDITIVE: u8 = Self::Additive as u8;
111 pub const DEP_ONLY: u8 = Self::DepOnly as u8;
112
113 pub fn is_valid_policy(policy: &u8) -> bool {
114 Self::try_from(*policy).is_ok()
115 }
116}
117
118impl TryFrom<u8> for UpgradePolicy {
119 type Error = ();
120 fn try_from(value: u8) -> Result<Self, Self::Error> {
121 match value {
122 x if x == Self::Compatible as u8 => Ok(Self::Compatible),
123 x if x == Self::Additive as u8 => Ok(Self::Additive),
124 x if x == Self::DepOnly as u8 => Ok(Self::DepOnly),
125 _ => Err(()),
126 }
127 }
128}
129
130#[derive(Debug, Serialize, Deserialize)]
132pub struct UpgradeCap {
133 pub id: UID,
134 pub package: ID,
135 pub version: u64,
136 pub policy: u8,
137}
138
139#[derive(Debug, Serialize, Deserialize)]
141pub struct UpgradeTicket {
142 pub cap: ID,
143 pub package: ID,
144 pub policy: u8,
145 pub digest: Vec<u8>,
146}
147
148#[derive(Debug, Serialize, Deserialize)]
150pub struct UpgradeReceipt {
151 pub cap: ID,
152 pub package: ID,
153}
154
155mod move_package_ext {
156 pub trait Sealed {}
157 impl Sealed for super::MovePackage {}
158}
159
160pub trait MovePackageExt: Sized + move_package_ext::Sealed {
161 fn new_initial<'p>(
162 modules: &[CompiledModule],
163 protocol_config: &ProtocolConfig,
164 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
165 ) -> Result<MovePackage, ExecutionError>;
166
167 fn new_upgraded<'p>(
168 &self,
169 storage_id: ObjectID,
170 modules: &[CompiledModule],
171 protocol_config: &ProtocolConfig,
172 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
173 ) -> Result<MovePackage, ExecutionError>;
174
175 fn new_system(
176 version: SequenceNumber,
177 modules: &[CompiledModule],
178 dependencies: impl IntoIterator<Item = ObjectID>,
179 ) -> MovePackage;
180
181 fn from_module_iter_with_type_origin_table<'p>(
182 storage_id: ObjectID,
183 self_id: ObjectID,
184 version: SequenceNumber,
185 modules: &[CompiledModule],
186 protocol_config: &ProtocolConfig,
187 type_origin_table: Vec<TypeOrigin>,
188 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
189 ) -> Result<MovePackage, ExecutionError>;
190
191 fn original_package_id(&self) -> ObjectID;
192
193 fn deserialize_module(
194 &self,
195 module: &Identifier,
196 binary_config: &BinaryConfig,
197 ) -> IotaResult<CompiledModule>;
198
199 fn normalize<S: Hash + Eq + Clone + ToString, Pool: normalized::StringPool<String = S>>(
200 &self,
201 pool: &mut Pool,
202 binary_config: &BinaryConfig,
203 include_code: bool,
204 ) -> IotaResult<BTreeMap<String, normalized::Module<S>>>;
205}
206
207impl MovePackageExt for MovePackage {
208 fn new_initial<'p>(
216 modules: &[CompiledModule],
217 protocol_config: &ProtocolConfig,
218 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
219 ) -> Result<MovePackage, ExecutionError> {
220 let module = modules
221 .first()
222 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
223 let runtime_id = ObjectID::new(module.address().into_bytes());
224 let storage_id = runtime_id;
225 let type_origin_table = build_initial_type_origin_table(modules);
226
227 MovePackage::from_module_iter_with_type_origin_table(
228 storage_id,
229 runtime_id,
230 Version::OBJECT_START,
231 modules,
232 protocol_config,
233 type_origin_table,
234 transitive_dependencies,
235 )
236 }
237
238 fn new_upgraded<'p>(
246 &self,
247 storage_id: ObjectID,
248 modules: &[CompiledModule],
249 protocol_config: &ProtocolConfig,
250 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
251 ) -> Result<MovePackage, ExecutionError> {
252 let module = modules
253 .first()
254 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
255 let runtime_id = ObjectID::new(module.address().into_bytes());
256 let type_origin_table = build_upgraded_type_origin_table(self, modules, storage_id)?;
257 let mut new_version = self.version();
258 new_version.increment().unwrap();
259
260 MovePackage::from_module_iter_with_type_origin_table(
261 storage_id,
262 runtime_id,
263 new_version,
264 modules,
265 protocol_config,
266 type_origin_table,
267 transitive_dependencies,
268 )
269 }
270
271 fn new_system(
272 version: SequenceNumber,
273 modules: &[CompiledModule],
274 dependencies: impl IntoIterator<Item = ObjectID>,
275 ) -> MovePackage {
276 let module = modules
277 .first()
278 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
279
280 let storage_id = ObjectID::new(module.address().into_bytes());
281 let type_origin_table = build_initial_type_origin_table(modules);
282
283 let linkage_table = BTreeMap::from_iter(dependencies.into_iter().map(|dep| {
284 let info = UpgradeInfo {
285 upgraded_id: dep,
286 upgraded_version: SequenceNumber::default(),
298 };
299 (dep, info)
300 }));
301
302 let module_map = BTreeMap::from_iter(modules.iter().map(|module| {
303 let name = Identifier::new_unchecked(module.name().as_str());
304 let mut bytes = Vec::new();
305 module
306 .serialize_with_version(module.version, &mut bytes)
307 .unwrap();
308 (name, bytes)
309 }));
310
311 MovePackage::new(
312 storage_id,
313 version,
314 module_map,
315 u64::MAX, type_origin_table,
317 linkage_table,
318 )
319 .expect("System packages are not subject to a size limit")
320 }
321
322 fn from_module_iter_with_type_origin_table<'p>(
323 storage_id: ObjectID,
324 self_id: ObjectID,
325 version: SequenceNumber,
326 modules: &[CompiledModule],
327 protocol_config: &ProtocolConfig,
328 type_origin_table: Vec<TypeOrigin>,
329 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
330 ) -> Result<MovePackage, ExecutionError> {
331 let mut module_map = BTreeMap::new();
332 let mut immediate_dependencies = BTreeSet::new();
333
334 for module in modules {
335 let name = Identifier::new_unchecked(module.name().as_str());
336
337 immediate_dependencies.extend(
338 module
339 .immediate_dependencies()
340 .into_iter()
341 .map(|dep| ObjectID::new(dep.address().into_bytes())),
342 );
343
344 let mut bytes = Vec::new();
345 let version = if protocol_config.move_binary_format_version() > VERSION_6 {
346 module.version
347 } else {
348 VERSION_6
349 };
350 module.serialize_with_version(version, &mut bytes).unwrap();
351 module_map.insert(name, bytes);
352 }
353
354 immediate_dependencies.remove(&self_id);
355 let linkage_table = build_linkage_table(
356 immediate_dependencies,
357 transitive_dependencies,
358 protocol_config,
359 )?;
360
361 Ok(MovePackage::new(
362 storage_id,
363 version,
364 module_map,
365 protocol_config.max_move_package_size(),
366 type_origin_table,
367 linkage_table,
368 )?)
369 }
370
371 fn original_package_id(&self) -> ObjectID {
379 if self.version == SequenceNumber::OBJECT_START {
380 return self.id;
382 }
383
384 let bytes = self.modules.values().next().expect("Empty module map");
385 let module = CompiledModule::deserialize_with_defaults(bytes)
389 .expect("A Move package contains a module that cannot be deserialized");
390 ObjectID::new(module.address().into_bytes())
391 }
392
393 fn deserialize_module(
394 &self,
395 module: &Identifier,
396 binary_config: &BinaryConfig,
397 ) -> IotaResult<CompiledModule> {
398 let bytes =
400 self.serialized_module_map()
401 .get(module)
402 .ok_or_else(|| IotaError::ModuleNotFound {
403 module_name: module.to_string(),
404 })?;
405
406 CompiledModule::deserialize_with_config(bytes, binary_config).map_err(|error| {
407 IotaError::ModuleDeserializationFailure {
408 error: error.to_string(),
409 }
410 })
411 }
412
413 fn normalize<S: Hash + Eq + Clone + ToString, Pool: normalized::StringPool<String = S>>(
416 &self,
417 pool: &mut Pool,
418 binary_config: &BinaryConfig,
419 include_code: bool,
420 ) -> IotaResult<BTreeMap<String, normalized::Module<S>>> {
421 normalize_modules(pool, self.modules.values(), binary_config, include_code)
422 }
423}
424
425impl UpgradeCap {
426 pub fn new(uid: ObjectID, package_id: ObjectID) -> Self {
429 UpgradeCap {
430 id: UID::new(uid),
431 package: ID::new(package_id),
432 version: 1,
433 policy: UpgradePolicy::COMPATIBLE,
434 }
435 }
436}
437
438impl UpgradeReceipt {
439 pub fn new(upgrade_ticket: UpgradeTicket, upgraded_package_id: ObjectID) -> Self {
442 UpgradeReceipt {
443 cap: upgrade_ticket.cap,
444 package: ID::new(upgraded_package_id),
445 }
446 }
447}
448
449pub fn is_test_fun(name: &str, module: &CompiledModule, fn_info_map: &FnInfoMap) -> bool {
451 let mod_handle = module.self_handle();
452 let mod_addr = IotaAddress::new(
453 module
454 .address_identifier_at(mod_handle.address)
455 .into_bytes(),
456 );
457 let mod_name = module.name().to_string();
458 let fn_info_key = FnInfoKey {
459 fn_name: name.to_string(),
460 mod_name,
461 mod_addr,
462 };
463 match fn_info_map.get(&fn_info_key) {
464 Some(fn_info) => fn_info.is_test,
465 None => false,
466 }
467}
468
469pub fn get_authenticator_version_from_fun(
470 name: &str,
471 module: &CompiledModule,
472 fn_info_map: &FnInfoMap,
473) -> Option<u8> {
474 let mod_handle = module.self_handle();
475 let mod_addr = IotaAddress::from(
476 module
477 .address_identifier_at(mod_handle.address)
478 .into_bytes(),
479 );
480 let mod_name = module.name().to_string();
481 let fn_info_key = FnInfoKey {
482 fn_name: name.to_string(),
483 mod_name,
484 mod_addr,
485 };
486 match fn_info_map.get(&fn_info_key) {
487 Some(FnInfo {
488 is_test: _,
489 authenticator_version: Some(v),
490 }) => Some(*v),
491 _ => None,
492 }
493}
494
495pub fn normalize_modules<
498 'a,
499 S: Hash + Eq + Clone + ToString,
500 Pool: normalized::StringPool<String = S>,
501 I,
502>(
503 pool: &mut Pool,
504 modules: I,
505 binary_config: &BinaryConfig,
506 include_code: bool,
507) -> IotaResult<BTreeMap<String, normalized::Module<S>>>
508where
509 I: Iterator<Item = &'a Vec<u8>>,
510{
511 let mut normalized_modules = BTreeMap::new();
512 for bytecode in modules {
513 let module =
514 CompiledModule::deserialize_with_config(bytecode, binary_config).map_err(|error| {
515 IotaError::ModuleDeserializationFailure {
516 error: error.to_string(),
517 }
518 })?;
519 let normalized_module = normalized::Module::new(pool, &module, include_code);
520 normalized_modules.insert(normalized_module.name().to_string(), normalized_module);
521 }
522 Ok(normalized_modules)
523}
524
525pub fn normalize_deserialized_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 include_code: bool,
536) -> BTreeMap<String, normalized::Module<S>>
537where
538 I: Iterator<Item = &'a CompiledModule>,
539{
540 let mut normalized_modules = BTreeMap::new();
541 for module in modules {
542 let normalized_module = normalized::Module::new(pool, module, include_code);
543 normalized_modules.insert(normalized_module.name().to_string(), normalized_module);
544 }
545 normalized_modules
546}
547
548fn build_linkage_table<'p>(
549 mut immediate_dependencies: BTreeSet<ObjectID>,
550 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
551 protocol_config: &ProtocolConfig,
552) -> Result<BTreeMap<ObjectID, UpgradeInfo>, ExecutionError> {
553 let mut linkage_table = BTreeMap::new();
554 let mut dep_linkage_tables = vec![];
555
556 for transitive_dep in transitive_dependencies.into_iter() {
557 let original_id = MovePackage::original_package_id(transitive_dep);
561
562 let imm_dep = immediate_dependencies.remove(&original_id);
563
564 if protocol_config.dependency_linkage_error() {
565 dep_linkage_tables.push(&transitive_dep.linkage_table);
566
567 let existing = linkage_table.insert(
568 original_id,
569 UpgradeInfo {
570 upgraded_id: transitive_dep.id,
571 upgraded_version: transitive_dep.version,
572 },
573 );
574
575 if existing.is_some() {
576 return Err(ExecutionErrorKind::InvalidLinkage.into());
577 }
578 } else {
579 if imm_dep {
580 dep_linkage_tables.push(&transitive_dep.linkage_table);
583 }
584 linkage_table.insert(
585 original_id,
586 UpgradeInfo {
587 upgraded_id: transitive_dep.id,
588 upgraded_version: transitive_dep.version,
589 },
590 );
591 }
592 }
593 if !immediate_dependencies.is_empty() {
595 return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into());
596 }
597
598 for dep_linkage_table in dep_linkage_tables {
600 for (original_id, dep_info) in dep_linkage_table {
601 let Some(our_info) = linkage_table.get(original_id) else {
602 return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into());
603 };
604
605 if our_info.upgraded_version < dep_info.upgraded_version {
606 return Err(ExecutionErrorKind::PublishUpgradeDependencyDowngrade.into());
607 }
608 }
609 }
610
611 Ok(linkage_table)
612}
613
614fn build_initial_type_origin_table(modules: &[CompiledModule]) -> Vec<TypeOrigin> {
615 modules
616 .iter()
617 .flat_map(|m| {
618 m.struct_defs()
619 .iter()
620 .map(|struct_def| {
621 let struct_handle = m.datatype_handle_at(struct_def.struct_handle);
622 let module_name = m.name().to_string();
623 let struct_name = m.identifier_at(struct_handle.name).to_string();
624 let package = ObjectID::new(m.self_id().address().into_bytes());
625 TypeOrigin {
626 module_name: Identifier::new_unchecked(module_name),
627 datatype_name: Identifier::new_unchecked(struct_name),
628 package,
629 }
630 })
631 .chain(m.enum_defs().iter().map(|enum_def| {
632 let enum_handle = m.datatype_handle_at(enum_def.enum_handle);
633 let module_name = m.name().to_string();
634 let enum_name = m.identifier_at(enum_handle.name).to_string();
635 let package = ObjectID::new(m.self_id().address().into_bytes());
636 TypeOrigin {
637 module_name: Identifier::new_unchecked(module_name),
638 datatype_name: Identifier::new_unchecked(enum_name),
639 package,
640 }
641 }))
642 })
643 .collect()
644}
645
646fn build_upgraded_type_origin_table(
647 predecessor: &MovePackage,
648 modules: &[CompiledModule],
649 storage_id: ObjectID,
650) -> Result<Vec<TypeOrigin>, ExecutionError> {
651 let mut new_table = vec![];
652 let mut existing_table = predecessor.type_origin_map();
653 for m in modules {
654 for struct_def in m.struct_defs() {
655 let struct_handle = m.datatype_handle_at(struct_def.struct_handle);
656 let module_name = Identifier::new_unchecked(m.name().as_str());
657 let struct_name =
658 Identifier::new_unchecked(m.identifier_at(struct_handle.name).as_str());
659 let mod_key = (module_name.clone(), struct_name.clone());
660 let package = existing_table.remove(&mod_key).unwrap_or(storage_id);
663 new_table.push(TypeOrigin {
664 module_name,
665 datatype_name: struct_name,
666 package,
667 });
668 }
669
670 for enum_def in m.enum_defs() {
671 let enum_handle = m.datatype_handle_at(enum_def.enum_handle);
672 let module_name = Identifier::new_unchecked(m.name().as_str());
673 let enum_name = Identifier::new_unchecked(m.identifier_at(enum_handle.name).as_str());
674 let mod_key = (module_name.clone(), enum_name.clone());
675 let package = existing_table.remove(&mod_key).unwrap_or(storage_id);
678 new_table.push(TypeOrigin {
679 module_name,
680 datatype_name: enum_name,
681 package,
682 });
683 }
684 }
685
686 if !existing_table.is_empty() {
687 Err(ExecutionError::from_kind(
688 ExecutionErrorKind::PackageUpgradeError {
689 kind: PackageUpgradeError::IncompatibleUpgrade,
690 },
691 ))
692 } else {
693 Ok(new_table)
694 }
695}
696
697#[serde_as]
699#[derive(Debug, Clone, Serialize, Deserialize)]
700pub struct RuntimeModuleMetadataWrapper {
701 pub version: u64,
702 #[serde_as(as = "Bytes")]
703 pub inner: Vec<u8>,
704}
705
706impl RuntimeModuleMetadataWrapper {
707 pub fn to_bcs_bytes(&self) -> Vec<u8> {
708 bcs::to_bytes(&self).unwrap()
710 }
711}
712
713impl From<RuntimeModuleMetadata> for RuntimeModuleMetadataWrapper {
714 fn from(metadata: RuntimeModuleMetadata) -> Self {
715 match metadata {
716 RuntimeModuleMetadata::V1(inner) => RuntimeModuleMetadataWrapper {
717 version: 1,
718 inner: inner.to_bcs_bytes(),
719 },
720 }
721 }
722}
723
724#[derive(Debug, Clone, Serialize, Deserialize)]
726pub enum RuntimeModuleMetadata {
727 V1(RuntimeModuleMetadataV1),
728}
729
730impl RuntimeModuleMetadata {
731 pub fn add_function_attribute(&mut self, function_name: String, attribute: IotaAttribute) {
732 match self {
733 RuntimeModuleMetadata::V1(metadata) => {
734 metadata.add_function_attribute(function_name, attribute)
735 }
736 }
737 }
738
739 pub fn is_empty(&self) -> bool {
740 match self {
741 RuntimeModuleMetadata::V1(metadata) => metadata.is_empty(),
742 }
743 }
744
745 pub fn fun_attributes_iter(
746 &self,
747 ) -> Box<dyn Iterator<Item = (&String, &Vec<IotaAttribute>)> + '_> {
748 match self {
749 RuntimeModuleMetadata::V1(metadata) => Box::new(metadata.fun_attributes.iter()),
750 }
751 }
752}
753
754impl Default for RuntimeModuleMetadata {
755 fn default() -> Self {
756 RuntimeModuleMetadata::V1(RuntimeModuleMetadataV1::default())
757 }
758}
759
760impl TryFrom<RuntimeModuleMetadataWrapper> for RuntimeModuleMetadata {
761 type Error = IotaError;
762
763 fn try_from(wrapper: RuntimeModuleMetadataWrapper) -> Result<Self, Self::Error> {
764 match wrapper.version {
765 1 => {
766 let inner: RuntimeModuleMetadataV1 =
767 bcs::from_bytes(&wrapper.inner).map_err(|e| {
768 IotaError::RuntimeModuleMetadataDeserialization {
769 error: e.to_string(),
770 }
771 })?;
772 Ok(RuntimeModuleMetadata::V1(inner))
773 }
774 _ => Err(IotaError::RuntimeModuleMetadataDeserialization {
775 error: format!(
776 "Unsupported runtime module metadata version: {}",
777 wrapper.version
778 ),
779 }),
780 }
781 }
782}
783
784#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
786pub enum IotaAttribute {
787 Authenticator(AuthenticatorAttribute),
788}
789
790#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
791pub struct AuthenticatorAttribute {
792 pub version: u8,
793}
794
795impl IotaAttribute {
796 pub fn authenticator_attribute(version: u8) -> Self {
797 IotaAttribute::Authenticator(AuthenticatorAttribute { version })
798 }
799}
800
801#[derive(Debug, Clone, Serialize, Deserialize, Default)]
803pub struct RuntimeModuleMetadataV1 {
804 pub fun_attributes: BTreeMap<String, Vec<IotaAttribute>>,
806}
807
808impl RuntimeModuleMetadataV1 {
809 pub fn add_function_attribute(&mut self, function_name: String, attribute: IotaAttribute) {
810 self.fun_attributes
811 .entry(function_name)
812 .or_default()
813 .push(attribute);
814 }
815
816 pub fn is_empty(&self) -> bool {
817 self.fun_attributes.is_empty()
818 }
819
820 pub fn to_bcs_bytes(&self) -> Vec<u8> {
821 bcs::to_bytes(&self).unwrap()
823 }
824}
825
826#[derive(Debug, Clone, Serialize, Deserialize)]
831pub enum PackageMetadata {
832 V1(PackageMetadataV1),
833}
834
835impl PackageMetadata {
836 pub fn new_v1(
839 uid: ObjectID,
840 storage_id: ObjectID,
841 runtime_id: ObjectID,
842 package_version: u64,
843 modules_metadata_map: BTreeMap<String, BTreeMap<String, TypeTag>>,
844 ) -> Self {
845 PackageMetadata::V1(PackageMetadataV1::new(
846 uid,
847 storage_id,
848 runtime_id,
849 package_version,
850 modules_metadata_map,
851 ))
852 }
853
854 pub fn type_(&self) -> StructTag {
855 match self {
856 PackageMetadata::V1(_) => PackageMetadataV1::type_(),
857 }
858 }
859
860 pub fn to_bcs_bytes(&self) -> Vec<u8> {
861 match self {
862 PackageMetadata::V1(inner) => inner.to_bcs_bytes(),
863 }
864 }
865}
866
867#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)]
868pub struct PackageMetadataKey {
869 dummy_field: bool,
873}
874
875impl PackageMetadataKey {
876 pub fn tag() -> StructTag {
877 StructTag::new(
878 IotaAddress::FRAMEWORK,
879 PACKAGE_METADATA_MODULE_NAME,
880 PACKAGE_METADATA_KEY_STRUCT_NAME,
881 Vec::new(),
882 )
883 }
884
885 pub fn to_bcs_bytes(&self) -> Vec<u8> {
886 bcs::to_bytes(&self).unwrap()
888 }
889}
890
891pub fn derive_package_metadata_id(package_storage_id: ObjectID) -> ObjectID {
892 derived_object::derive_object_id(
893 package_storage_id,
894 &PackageMetadataKey::tag().into(),
895 &PackageMetadataKey::default().to_bcs_bytes(),
896 )
897 .unwrap() }
899
900#[derive(Debug, Clone, Serialize, Deserialize)]
902pub struct PackageMetadataV1 {
903 pub uid: UID,
905 pub storage_id: ID,
909 pub runtime_id: ID,
912 pub package_version: u64,
914 pub modules_metadata: VecMap<String, ModuleMetadataV1>,
916}
917
918impl PackageMetadataV1 {
919 fn new(
920 uid: ObjectID,
921 storage_id: ObjectID,
922 runtime_id: ObjectID,
923 package_version: u64,
924 modules_metadata_map: BTreeMap<String, BTreeMap<String, TypeTag>>,
925 ) -> Self {
926 let mut modules_metadata = VecMap { contents: vec![] };
927
928 for (module_name, module_metadata_map) in modules_metadata_map {
929 let mut module_metadata = ModuleMetadataV1 {
930 authenticator_metadata: vec![],
931 };
932 for (function_name, account_type) in module_metadata_map {
933 module_metadata
934 .authenticator_metadata
935 .push(AuthenticatorMetadataV1 {
936 function_name,
937 account_type,
938 });
939 }
940 modules_metadata.contents.push(Entry {
941 key: module_name,
942 value: module_metadata,
943 });
944 }
945
946 Self {
947 uid: UID::new(uid),
948 storage_id: ID::new(storage_id),
949 runtime_id: ID::new(runtime_id),
950 package_version,
951 modules_metadata,
952 }
953 }
954
955 pub fn type_() -> StructTag {
956 StructTag::new(
957 IotaAddress::FRAMEWORK,
958 PACKAGE_METADATA_MODULE_NAME,
959 PACKAGE_METADATA_V1_STRUCT_NAME,
960 vec![],
961 )
962 }
963
964 pub fn to_bcs_bytes(&self) -> Vec<u8> {
965 bcs::to_bytes(&self).unwrap()
967 }
968}
969
970#[derive(Debug, Clone, Serialize, Deserialize)]
972pub struct ModuleMetadataV1 {
973 pub authenticator_metadata: Vec<AuthenticatorMetadataV1>,
974}
975
976impl ModuleMetadataV1 {
977 pub fn is_empty(&self) -> bool {
978 self.authenticator_metadata.is_empty()
979 }
980}
981
982#[serde_as]
984#[derive(Debug, Clone, Serialize, Deserialize)]
985pub struct AuthenticatorMetadataV1 {
986 pub function_name: String,
987 #[serde_as(as = "TypeName")]
988 pub account_type: TypeTag,
989}