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