1use std::{
37 collections::{BTreeMap, BTreeSet},
38 hash::Hash,
39};
40
41use derive_more::Display;
42use fastcrypto::hash::HashFunction;
43use iota_protocol_config::ProtocolConfig;
44use move_binary_format::{
45 binary_config::BinaryConfig, file_format::CompiledModule, file_format_common::VERSION_6,
46 normalized,
47};
48use move_core_types::{
49 account_address::AccountAddress,
50 ident_str,
51 identifier::{IdentStr, Identifier},
52 language_storage::{ModuleId, StructTag},
53};
54use schemars::JsonSchema;
55use serde::{Deserialize, Serialize};
56use serde_with::{Bytes, serde_as};
57
58use crate::{
59 IOTA_FRAMEWORK_ADDRESS,
60 base_types::{ObjectID, SequenceNumber},
61 collection_types::{Entry, VecMap},
62 crypto::DefaultHash,
63 derived_object,
64 error::{ExecutionError, ExecutionErrorKind, IotaError, IotaResult},
65 execution_status::PackageUpgradeError,
66 id::{ID, UID},
67 object::OBJECT_START_VERSION,
68 type_input::TypeName,
69};
70
71pub const PACKAGE_MODULE_NAME: &IdentStr = ident_str!("package");
72pub const UPGRADECAP_STRUCT_NAME: &IdentStr = ident_str!("UpgradeCap");
73pub const UPGRADETICKET_STRUCT_NAME: &IdentStr = ident_str!("UpgradeTicket");
74pub const UPGRADERECEIPT_STRUCT_NAME: &IdentStr = ident_str!("UpgradeReceipt");
75
76pub const PACKAGE_METADATA_MODULE_NAME: &IdentStr = ident_str!("package_metadata");
77pub const PACKAGE_METADATA_V1_STRUCT_NAME: &IdentStr = ident_str!("PackageMetadataV1");
78pub const PACKAGE_METADATA_KEY_STRUCT_NAME: &IdentStr = ident_str!("PackageMetadataKey");
79
80#[derive(Clone, Debug)]
81pub struct FnInfo {
83 pub is_test: bool,
86 pub authenticator_version: Option<u8>,
89}
90
91#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
92pub struct FnInfoKey {
94 pub fn_name: String,
95 pub mod_name: String,
96 pub mod_addr: AccountAddress,
97}
98
99pub type FnInfoMap = BTreeMap<FnInfoKey, FnInfo>;
101
102#[derive(
113 Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, Hash, JsonSchema,
114)]
115pub struct TypeOrigin {
116 pub module_name: String,
118 #[serde(alias = "struct_name")]
123 pub datatype_name: String,
124 pub package: ObjectID,
126}
127
128#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash, JsonSchema)]
135pub struct UpgradeInfo {
136 pub upgraded_id: ObjectID,
138 pub upgraded_version: SequenceNumber,
140}
141
142#[serde_as]
145#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)]
146pub struct MovePackage {
147 pub(crate) id: ObjectID,
149 pub(crate) version: SequenceNumber,
161 #[serde_as(as = "BTreeMap<_, Bytes>")]
166 pub(crate) module_map: BTreeMap<String, Vec<u8>>,
167
168 pub(crate) type_origin_table: Vec<TypeOrigin>,
174
175 pub(crate) linkage_table: BTreeMap<ObjectID, UpgradeInfo>,
179}
180
181#[repr(u8)]
186#[derive(Display, Debug, Clone, Copy)]
187pub enum UpgradePolicy {
188 #[display("COMPATIBLE")]
189 Compatible = 0,
190 #[display("ADDITIVE")]
191 Additive = 128,
192 #[display("DEP_ONLY")]
193 DepOnly = 192,
194}
195
196impl UpgradePolicy {
197 pub const COMPATIBLE: u8 = Self::Compatible as u8;
199 pub const ADDITIVE: u8 = Self::Additive as u8;
200 pub const DEP_ONLY: u8 = Self::DepOnly as u8;
201
202 pub fn is_valid_policy(policy: &u8) -> bool {
203 Self::try_from(*policy).is_ok()
204 }
205}
206
207impl TryFrom<u8> for UpgradePolicy {
208 type Error = ();
209 fn try_from(value: u8) -> Result<Self, Self::Error> {
210 match value {
211 x if x == Self::Compatible as u8 => Ok(Self::Compatible),
212 x if x == Self::Additive as u8 => Ok(Self::Additive),
213 x if x == Self::DepOnly as u8 => Ok(Self::DepOnly),
214 _ => Err(()),
215 }
216 }
217}
218
219#[derive(Debug, Serialize, Deserialize)]
221pub struct UpgradeCap {
222 pub id: UID,
223 pub package: ID,
224 pub version: u64,
225 pub policy: u8,
226}
227
228#[derive(Debug, Serialize, Deserialize)]
230pub struct UpgradeTicket {
231 pub cap: ID,
232 pub package: ID,
233 pub policy: u8,
234 pub digest: Vec<u8>,
235}
236
237#[derive(Debug, Serialize, Deserialize)]
239pub struct UpgradeReceipt {
240 pub cap: ID,
241 pub package: ID,
242}
243
244impl MovePackage {
245 pub fn new(
251 id: ObjectID,
252 version: SequenceNumber,
253 module_map: BTreeMap<String, Vec<u8>>,
254 max_move_package_size: u64,
255 type_origin_table: Vec<TypeOrigin>,
256 linkage_table: BTreeMap<ObjectID, UpgradeInfo>,
257 ) -> Result<Self, ExecutionError> {
258 let pkg = Self {
259 id,
260 version,
261 module_map,
262 type_origin_table,
263 linkage_table,
264 };
265 let object_size = pkg.size() as u64;
266 if object_size > max_move_package_size {
267 return Err(ExecutionErrorKind::MovePackageTooBig {
268 object_size,
269 max_object_size: max_move_package_size,
270 }
271 .into());
272 }
273 Ok(pkg)
274 }
275
276 pub fn digest(&self) -> [u8; 32] {
278 Self::compute_digest_for_modules_and_deps(
279 self.module_map.values(),
280 self.linkage_table
281 .values()
282 .map(|UpgradeInfo { upgraded_id, .. }| upgraded_id),
283 )
284 }
285
286 pub fn compute_digest_for_modules_and_deps<'a>(
290 modules: impl IntoIterator<Item = &'a Vec<u8>>,
291 object_ids: impl IntoIterator<Item = &'a ObjectID>,
292 ) -> [u8; 32] {
293 let mut components = object_ids
294 .into_iter()
295 .map(|o| ***o)
296 .chain(
297 modules
298 .into_iter()
299 .map(|module| DefaultHash::digest(module).digest),
300 )
301 .collect::<Vec<_>>();
302
303 components.sort();
306
307 let mut digest = DefaultHash::default();
308 for c in components {
309 digest.update(c);
310 }
311 digest.finalize().digest
312 }
313
314 pub fn new_initial<'p>(
322 modules: &[CompiledModule],
323 protocol_config: &ProtocolConfig,
324 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
325 ) -> Result<Self, ExecutionError> {
326 let module = modules
327 .first()
328 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
329 let runtime_id = ObjectID::from(*module.address());
330 let storage_id = runtime_id;
331 let type_origin_table = build_initial_type_origin_table(modules);
332 Self::from_module_iter_with_type_origin_table(
333 storage_id,
334 runtime_id,
335 OBJECT_START_VERSION,
336 modules,
337 protocol_config,
338 type_origin_table,
339 transitive_dependencies,
340 )
341 }
342
343 pub fn new_upgraded<'p>(
351 &self,
352 storage_id: ObjectID,
353 modules: &[CompiledModule],
354 protocol_config: &ProtocolConfig,
355 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
356 ) -> Result<Self, ExecutionError> {
357 let module = modules
358 .first()
359 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
360 let runtime_id = ObjectID::from(*module.address());
361 let type_origin_table = build_upgraded_type_origin_table(self, modules, storage_id)?;
362 let mut new_version = self.version();
363 new_version.increment();
364 Self::from_module_iter_with_type_origin_table(
365 storage_id,
366 runtime_id,
367 new_version,
368 modules,
369 protocol_config,
370 type_origin_table,
371 transitive_dependencies,
372 )
373 }
374
375 pub fn new_system(
376 version: SequenceNumber,
377 modules: &[CompiledModule],
378 dependencies: impl IntoIterator<Item = ObjectID>,
379 ) -> Self {
380 let module = modules
381 .first()
382 .expect("Tried to build a Move package from an empty iterator of Compiled modules");
383
384 let storage_id = ObjectID::from(*module.address());
385 let type_origin_table = build_initial_type_origin_table(modules);
386
387 let linkage_table = BTreeMap::from_iter(dependencies.into_iter().map(|dep| {
388 let info = UpgradeInfo {
389 upgraded_id: dep,
390 upgraded_version: SequenceNumber::new(),
402 };
403 (dep, info)
404 }));
405
406 let module_map = BTreeMap::from_iter(modules.iter().map(|module| {
407 let name = module.name().to_string();
408 let mut bytes = Vec::new();
409 module
410 .serialize_with_version(module.version, &mut bytes)
411 .unwrap();
412 (name, bytes)
413 }));
414
415 Self::new(
416 storage_id,
417 version,
418 module_map,
419 u64::MAX, type_origin_table,
421 linkage_table,
422 )
423 .expect("System packages are not subject to a size limit")
424 }
425
426 fn from_module_iter_with_type_origin_table<'p>(
427 storage_id: ObjectID,
428 self_id: ObjectID,
429 version: SequenceNumber,
430 modules: &[CompiledModule],
431 protocol_config: &ProtocolConfig,
432 type_origin_table: Vec<TypeOrigin>,
433 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
434 ) -> Result<Self, ExecutionError> {
435 let mut module_map = BTreeMap::new();
436 let mut immediate_dependencies = BTreeSet::new();
437
438 for module in modules {
439 let name = module.name().to_string();
440
441 immediate_dependencies.extend(
442 module
443 .immediate_dependencies()
444 .into_iter()
445 .map(|dep| ObjectID::from(*dep.address())),
446 );
447
448 let mut bytes = Vec::new();
449 let version = if protocol_config.move_binary_format_version() > VERSION_6 {
450 module.version
451 } else {
452 VERSION_6
453 };
454 module.serialize_with_version(version, &mut bytes).unwrap();
455 module_map.insert(name, bytes);
456 }
457
458 immediate_dependencies.remove(&self_id);
459 let linkage_table = build_linkage_table(
460 immediate_dependencies,
461 transitive_dependencies,
462 protocol_config,
463 )?;
464 Self::new(
465 storage_id,
466 version,
467 module_map,
468 protocol_config.max_move_package_size(),
469 type_origin_table,
470 linkage_table,
471 )
472 }
473
474 pub fn get_module(&self, storage_id: &ModuleId) -> Option<&Vec<u8>> {
480 if self.id != ObjectID::from(*storage_id.address()) {
481 None
482 } else {
483 self.module_map.get(&storage_id.name().to_string())
484 }
485 }
486
487 pub fn size(&self) -> usize {
489 let module_map_size = self
490 .module_map
491 .iter()
492 .map(|(name, module)| name.len() + module.len())
493 .sum::<usize>();
494 let type_origin_table_size = self
495 .type_origin_table
496 .iter()
497 .map(
498 |TypeOrigin {
499 module_name,
500 datatype_name: struct_name,
501 ..
502 }| module_name.len() + struct_name.len() + ObjectID::LENGTH,
503 )
504 .sum::<usize>();
505
506 let linkage_table_size = self.linkage_table.len()
507 * (ObjectID::LENGTH
508 + (
509 ObjectID::LENGTH + 8
510 ));
512
513 8 + module_map_size + type_origin_table_size + linkage_table_size
514 }
515
516 pub fn id(&self) -> ObjectID {
518 self.id
519 }
520
521 pub fn version(&self) -> SequenceNumber {
522 self.version
523 }
524
525 pub fn decrement_version(&mut self) {
526 self.version.decrement();
527 }
528
529 pub fn increment_version(&mut self) {
530 self.version.increment();
531 }
532
533 pub fn object_size_for_gas_metering(&self) -> usize {
535 self.size()
536 }
537
538 pub fn serialized_module_map(&self) -> &BTreeMap<String, Vec<u8>> {
539 &self.module_map
540 }
541
542 pub fn type_origin_table(&self) -> &Vec<TypeOrigin> {
543 &self.type_origin_table
544 }
545
546 pub fn type_origin_map(&self) -> BTreeMap<(String, String), ObjectID> {
547 self.type_origin_table
548 .iter()
549 .map(
550 |TypeOrigin {
551 module_name,
552 datatype_name: struct_name,
553 package,
554 }| { ((module_name.clone(), struct_name.clone()), *package) },
555 )
556 .collect()
557 }
558
559 pub fn linkage_table(&self) -> &BTreeMap<ObjectID, UpgradeInfo> {
560 &self.linkage_table
561 }
562
563 pub fn original_package_id(&self) -> ObjectID {
571 if self.version == OBJECT_START_VERSION {
572 return self.id;
574 }
575
576 let bytes = self.module_map.values().next().expect("Empty module map");
577 let module = CompiledModule::deserialize_with_defaults(bytes)
581 .expect("A Move package contains a module that cannot be deserialized");
582 (*module.address()).into()
583 }
584
585 pub fn deserialize_module(
586 &self,
587 module: &Identifier,
588 binary_config: &BinaryConfig,
589 ) -> IotaResult<CompiledModule> {
590 let bytes = self
592 .serialized_module_map()
593 .get(module.as_str())
594 .ok_or_else(|| IotaError::ModuleNotFound {
595 module_name: module.to_string(),
596 })?;
597 CompiledModule::deserialize_with_config(bytes, binary_config).map_err(|error| {
598 IotaError::ModuleDeserializationFailure {
599 error: error.to_string(),
600 }
601 })
602 }
603 pub fn normalize<S: Hash + Eq + Clone + ToString, Pool: normalized::StringPool<String = S>>(
606 &self,
607 pool: &mut Pool,
608 binary_config: &BinaryConfig,
609 include_code: bool,
610 ) -> IotaResult<BTreeMap<String, normalized::Module<S>>> {
611 normalize_modules(pool, self.module_map.values(), binary_config, include_code)
612 }
613}
614
615impl UpgradeCap {
616 pub fn type_() -> StructTag {
617 StructTag {
618 address: IOTA_FRAMEWORK_ADDRESS,
619 module: PACKAGE_MODULE_NAME.to_owned(),
620 name: UPGRADECAP_STRUCT_NAME.to_owned(),
621 type_params: vec![],
622 }
623 }
624
625 pub fn new(uid: ObjectID, package_id: ObjectID) -> Self {
628 UpgradeCap {
629 id: UID::new(uid),
630 package: ID::new(package_id),
631 version: 1,
632 policy: UpgradePolicy::COMPATIBLE,
633 }
634 }
635}
636
637impl UpgradeTicket {
638 pub fn type_() -> StructTag {
639 StructTag {
640 address: IOTA_FRAMEWORK_ADDRESS,
641 module: PACKAGE_MODULE_NAME.to_owned(),
642 name: UPGRADETICKET_STRUCT_NAME.to_owned(),
643 type_params: vec![],
644 }
645 }
646}
647
648impl UpgradeReceipt {
649 pub fn type_() -> StructTag {
650 StructTag {
651 address: IOTA_FRAMEWORK_ADDRESS,
652 module: PACKAGE_MODULE_NAME.to_owned(),
653 name: UPGRADERECEIPT_STRUCT_NAME.to_owned(),
654 type_params: vec![],
655 }
656 }
657
658 pub fn new(upgrade_ticket: UpgradeTicket, upgraded_package_id: ObjectID) -> Self {
661 UpgradeReceipt {
662 cap: upgrade_ticket.cap,
663 package: ID::new(upgraded_package_id),
664 }
665 }
666}
667
668pub fn is_test_fun(name: &IdentStr, module: &CompiledModule, fn_info_map: &FnInfoMap) -> bool {
670 let fn_name = name.to_string();
671 let mod_handle = module.self_handle();
672 let mod_addr = *module.address_identifier_at(mod_handle.address);
673 let mod_name = module.name().to_string();
674 let fn_info_key = FnInfoKey {
675 fn_name,
676 mod_name,
677 mod_addr,
678 };
679 match fn_info_map.get(&fn_info_key) {
680 Some(fn_info) => fn_info.is_test,
681 None => false,
682 }
683}
684
685pub fn get_authenticator_version_from_fun(
686 name: &IdentStr,
687 module: &CompiledModule,
688 fn_info_map: &FnInfoMap,
689) -> Option<u8> {
690 let fn_name = name.to_string();
691 let mod_handle = module.self_handle();
692 let mod_addr = *module.address_identifier_at(mod_handle.address);
693 let mod_name = module.name().to_string();
694 let fn_info_key = FnInfoKey {
695 fn_name,
696 mod_name,
697 mod_addr,
698 };
699 match fn_info_map.get(&fn_info_key) {
700 Some(FnInfo {
701 is_test: _,
702 authenticator_version: Some(v),
703 }) => Some(*v),
704 _ => None,
705 }
706}
707
708pub fn normalize_modules<
711 'a,
712 S: Hash + Eq + Clone + ToString,
713 Pool: normalized::StringPool<String = S>,
714 I,
715>(
716 pool: &mut Pool,
717 modules: I,
718 binary_config: &BinaryConfig,
719 include_code: bool,
720) -> IotaResult<BTreeMap<String, normalized::Module<S>>>
721where
722 I: Iterator<Item = &'a Vec<u8>>,
723{
724 let mut normalized_modules = BTreeMap::new();
725 for bytecode in modules {
726 let module =
727 CompiledModule::deserialize_with_config(bytecode, binary_config).map_err(|error| {
728 IotaError::ModuleDeserializationFailure {
729 error: error.to_string(),
730 }
731 })?;
732 let normalized_module = normalized::Module::new(pool, &module, include_code);
733 normalized_modules.insert(normalized_module.name().to_string(), normalized_module);
734 }
735 Ok(normalized_modules)
736}
737
738pub fn normalize_deserialized_modules<
741 'a,
742 S: Hash + Eq + Clone + ToString,
743 Pool: normalized::StringPool<String = S>,
744 I,
745>(
746 pool: &mut Pool,
747 modules: I,
748 include_code: bool,
749) -> BTreeMap<String, normalized::Module<S>>
750where
751 I: Iterator<Item = &'a CompiledModule>,
752{
753 let mut normalized_modules = BTreeMap::new();
754 for module in modules {
755 let normalized_module = normalized::Module::new(pool, module, include_code);
756 normalized_modules.insert(normalized_module.name().to_string(), normalized_module);
757 }
758 normalized_modules
759}
760
761fn build_linkage_table<'p>(
762 mut immediate_dependencies: BTreeSet<ObjectID>,
763 transitive_dependencies: impl IntoIterator<Item = &'p MovePackage>,
764 protocol_config: &ProtocolConfig,
765) -> Result<BTreeMap<ObjectID, UpgradeInfo>, ExecutionError> {
766 let mut linkage_table = BTreeMap::new();
767 let mut dep_linkage_tables = vec![];
768
769 for transitive_dep in transitive_dependencies.into_iter() {
770 let original_id = transitive_dep.original_package_id();
774
775 let imm_dep = immediate_dependencies.remove(&original_id);
776
777 if protocol_config.dependency_linkage_error() {
778 dep_linkage_tables.push(&transitive_dep.linkage_table);
779
780 let existing = linkage_table.insert(
781 original_id,
782 UpgradeInfo {
783 upgraded_id: transitive_dep.id,
784 upgraded_version: transitive_dep.version,
785 },
786 );
787
788 if existing.is_some() {
789 return Err(ExecutionErrorKind::InvalidLinkage.into());
790 }
791 } else {
792 if imm_dep {
793 dep_linkage_tables.push(&transitive_dep.linkage_table);
796 }
797 linkage_table.insert(
798 original_id,
799 UpgradeInfo {
800 upgraded_id: transitive_dep.id,
801 upgraded_version: transitive_dep.version,
802 },
803 );
804 }
805 }
806 if !immediate_dependencies.is_empty() {
808 return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into());
809 }
810
811 for dep_linkage_table in dep_linkage_tables {
813 for (original_id, dep_info) in dep_linkage_table {
814 let Some(our_info) = linkage_table.get(original_id) else {
815 return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into());
816 };
817
818 if our_info.upgraded_version < dep_info.upgraded_version {
819 return Err(ExecutionErrorKind::PublishUpgradeDependencyDowngrade.into());
820 }
821 }
822 }
823
824 Ok(linkage_table)
825}
826
827fn build_initial_type_origin_table(modules: &[CompiledModule]) -> Vec<TypeOrigin> {
828 modules
829 .iter()
830 .flat_map(|m| {
831 m.struct_defs()
832 .iter()
833 .map(|struct_def| {
834 let struct_handle = m.datatype_handle_at(struct_def.struct_handle);
835 let module_name = m.name().to_string();
836 let struct_name = m.identifier_at(struct_handle.name).to_string();
837 let package: ObjectID = (*m.self_id().address()).into();
838 TypeOrigin {
839 module_name,
840 datatype_name: struct_name,
841 package,
842 }
843 })
844 .chain(m.enum_defs().iter().map(|enum_def| {
845 let enum_handle = m.datatype_handle_at(enum_def.enum_handle);
846 let module_name = m.name().to_string();
847 let enum_name = m.identifier_at(enum_handle.name).to_string();
848 let package: ObjectID = (*m.self_id().address()).into();
849 TypeOrigin {
850 module_name,
851 datatype_name: enum_name,
852 package,
853 }
854 }))
855 })
856 .collect()
857}
858
859fn build_upgraded_type_origin_table(
860 predecessor: &MovePackage,
861 modules: &[CompiledModule],
862 storage_id: ObjectID,
863) -> Result<Vec<TypeOrigin>, ExecutionError> {
864 let mut new_table = vec![];
865 let mut existing_table = predecessor.type_origin_map();
866 for m in modules {
867 for struct_def in m.struct_defs() {
868 let struct_handle = m.datatype_handle_at(struct_def.struct_handle);
869 let module_name = m.name().to_string();
870 let struct_name = m.identifier_at(struct_handle.name).to_string();
871 let mod_key = (module_name.clone(), struct_name.clone());
872 let package = existing_table.remove(&mod_key).unwrap_or(storage_id);
875 new_table.push(TypeOrigin {
876 module_name,
877 datatype_name: struct_name,
878 package,
879 });
880 }
881
882 for enum_def in m.enum_defs() {
883 let enum_handle = m.datatype_handle_at(enum_def.enum_handle);
884 let module_name = m.name().to_string();
885 let enum_name = m.identifier_at(enum_handle.name).to_string();
886 let mod_key = (module_name.clone(), enum_name.clone());
887 let package = existing_table.remove(&mod_key).unwrap_or(storage_id);
890 new_table.push(TypeOrigin {
891 module_name,
892 datatype_name: enum_name,
893 package,
894 });
895 }
896 }
897
898 if !existing_table.is_empty() {
899 Err(ExecutionError::from_kind(
900 ExecutionErrorKind::PackageUpgradeError {
901 upgrade_error: PackageUpgradeError::IncompatibleUpgrade,
902 },
903 ))
904 } else {
905 Ok(new_table)
906 }
907}
908
909#[serde_as]
911#[derive(Debug, Clone, Serialize, Deserialize)]
912pub struct RuntimeModuleMetadataWrapper {
913 pub version: u64,
914 #[serde_as(as = "Bytes")]
915 pub inner: Vec<u8>,
916}
917
918impl RuntimeModuleMetadataWrapper {
919 pub fn to_bcs_bytes(&self) -> Vec<u8> {
920 bcs::to_bytes(&self).unwrap()
922 }
923}
924
925impl From<RuntimeModuleMetadata> for RuntimeModuleMetadataWrapper {
926 fn from(metadata: RuntimeModuleMetadata) -> Self {
927 match metadata {
928 RuntimeModuleMetadata::V1(inner) => RuntimeModuleMetadataWrapper {
929 version: 1,
930 inner: inner.to_bcs_bytes(),
931 },
932 }
933 }
934}
935
936#[derive(Debug, Clone, Serialize, Deserialize)]
938pub enum RuntimeModuleMetadata {
939 V1(RuntimeModuleMetadataV1),
940}
941
942impl RuntimeModuleMetadata {
943 pub fn add_function_attribute(&mut self, function_name: String, attribute: IotaAttribute) {
944 match self {
945 RuntimeModuleMetadata::V1(metadata) => {
946 metadata.add_function_attribute(function_name, attribute)
947 }
948 }
949 }
950
951 pub fn is_empty(&self) -> bool {
952 match self {
953 RuntimeModuleMetadata::V1(metadata) => metadata.is_empty(),
954 }
955 }
956
957 pub fn fun_attributes_iter(
958 &self,
959 ) -> Box<dyn Iterator<Item = (&String, &Vec<IotaAttribute>)> + '_> {
960 match self {
961 RuntimeModuleMetadata::V1(metadata) => Box::new(metadata.fun_attributes.iter()),
962 }
963 }
964}
965
966impl Default for RuntimeModuleMetadata {
967 fn default() -> Self {
968 RuntimeModuleMetadata::V1(RuntimeModuleMetadataV1::default())
969 }
970}
971
972impl TryFrom<RuntimeModuleMetadataWrapper> for RuntimeModuleMetadata {
973 type Error = IotaError;
974
975 fn try_from(wrapper: RuntimeModuleMetadataWrapper) -> Result<Self, Self::Error> {
976 match wrapper.version {
977 1 => {
978 let inner: RuntimeModuleMetadataV1 =
979 bcs::from_bytes(&wrapper.inner).map_err(|e| {
980 IotaError::RuntimeModuleMetadataDeserialization {
981 error: e.to_string(),
982 }
983 })?;
984 Ok(RuntimeModuleMetadata::V1(inner))
985 }
986 _ => Err(IotaError::RuntimeModuleMetadataDeserialization {
987 error: format!(
988 "Unsupported runtime module metadata version: {}",
989 wrapper.version
990 ),
991 }),
992 }
993 }
994}
995
996#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
998pub enum IotaAttribute {
999 Authenticator(AuthenticatorAttribute),
1000}
1001
1002#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
1003pub struct AuthenticatorAttribute {
1004 pub version: u8,
1005}
1006
1007impl IotaAttribute {
1008 pub fn authenticator_attribute(version: u8) -> Self {
1009 IotaAttribute::Authenticator(AuthenticatorAttribute { version })
1010 }
1011}
1012
1013#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1015pub struct RuntimeModuleMetadataV1 {
1016 pub fun_attributes: BTreeMap<String, Vec<IotaAttribute>>,
1018}
1019
1020impl RuntimeModuleMetadataV1 {
1021 pub fn add_function_attribute(&mut self, function_name: String, attribute: IotaAttribute) {
1022 self.fun_attributes
1023 .entry(function_name)
1024 .or_default()
1025 .push(attribute);
1026 }
1027
1028 pub fn is_empty(&self) -> bool {
1029 self.fun_attributes.is_empty()
1030 }
1031
1032 pub fn to_bcs_bytes(&self) -> Vec<u8> {
1033 bcs::to_bytes(&self).unwrap()
1035 }
1036}
1037
1038#[derive(Debug, Clone, Serialize, Deserialize)]
1043pub enum PackageMetadata {
1044 V1(PackageMetadataV1),
1045}
1046
1047impl PackageMetadata {
1048 pub fn new_v1(
1051 uid: ObjectID,
1052 storage_id: ObjectID,
1053 runtime_id: ObjectID,
1054 package_version: u64,
1055 modules_metadata_map: BTreeMap<String, BTreeMap<String, TypeName>>,
1056 ) -> Self {
1057 PackageMetadata::V1(PackageMetadataV1::new(
1058 uid,
1059 storage_id,
1060 runtime_id,
1061 package_version,
1062 modules_metadata_map,
1063 ))
1064 }
1065
1066 pub fn type_(&self) -> StructTag {
1067 match self {
1068 PackageMetadata::V1(_) => PackageMetadataV1::type_(),
1069 }
1070 }
1071
1072 pub fn to_bcs_bytes(&self) -> Vec<u8> {
1073 match self {
1074 PackageMetadata::V1(inner) => inner.to_bcs_bytes(),
1075 }
1076 }
1077}
1078
1079#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)]
1080pub struct PackageMetadataKey {
1081 dummy_field: bool,
1085}
1086
1087impl PackageMetadataKey {
1088 pub fn tag() -> StructTag {
1089 StructTag {
1090 address: IOTA_FRAMEWORK_ADDRESS,
1091 module: PACKAGE_METADATA_MODULE_NAME.to_owned(),
1092 name: PACKAGE_METADATA_KEY_STRUCT_NAME.to_owned(),
1093 type_params: Vec::new(),
1094 }
1095 }
1096
1097 pub fn to_bcs_bytes(&self) -> Vec<u8> {
1098 bcs::to_bytes(&self).unwrap()
1100 }
1101}
1102
1103pub fn derive_package_metadata_id(package_storage_id: ObjectID) -> ObjectID {
1104 derived_object::derive_object_id(
1105 package_storage_id,
1106 &PackageMetadataKey::tag().into(),
1107 &PackageMetadataKey::default().to_bcs_bytes(),
1108 )
1109 .unwrap() }
1111
1112#[derive(Debug, Clone, Serialize, Deserialize)]
1114pub struct PackageMetadataV1 {
1115 pub uid: UID,
1117 pub storage_id: ID,
1121 pub runtime_id: ID,
1124 pub package_version: u64,
1126 pub modules_metadata: VecMap<String, ModuleMetadataV1>,
1128}
1129
1130impl PackageMetadataV1 {
1131 fn new(
1132 uid: ObjectID,
1133 storage_id: ObjectID,
1134 runtime_id: ObjectID,
1135 package_version: u64,
1136 modules_metadata_map: BTreeMap<String, BTreeMap<String, TypeName>>,
1137 ) -> Self {
1138 let mut modules_metadata = VecMap { contents: vec![] };
1139
1140 for (module_name, module_metadata_map) in modules_metadata_map {
1141 let mut module_metadata = ModuleMetadataV1 {
1142 authenticator_metadata: vec![],
1143 };
1144 for (function_name, account_type) in module_metadata_map {
1145 module_metadata
1146 .authenticator_metadata
1147 .push(AuthenticatorMetadataV1 {
1148 function_name,
1149 account_type,
1150 });
1151 }
1152 modules_metadata.contents.push(Entry {
1153 key: module_name,
1154 value: module_metadata,
1155 });
1156 }
1157
1158 Self {
1159 uid: UID::new(uid),
1160 storage_id: ID::new(storage_id),
1161 runtime_id: ID::new(runtime_id),
1162 package_version,
1163 modules_metadata,
1164 }
1165 }
1166
1167 pub fn type_() -> StructTag {
1168 StructTag {
1169 address: IOTA_FRAMEWORK_ADDRESS,
1170 module: PACKAGE_METADATA_MODULE_NAME.to_owned(),
1171 name: PACKAGE_METADATA_V1_STRUCT_NAME.to_owned(),
1172 type_params: vec![],
1173 }
1174 }
1175
1176 pub fn to_bcs_bytes(&self) -> Vec<u8> {
1177 bcs::to_bytes(&self).unwrap()
1179 }
1180}
1181
1182#[derive(Debug, Clone, Serialize, Deserialize)]
1184pub struct ModuleMetadataV1 {
1185 pub authenticator_metadata: Vec<AuthenticatorMetadataV1>,
1186}
1187
1188impl ModuleMetadataV1 {
1189 pub fn is_empty(&self) -> bool {
1190 self.authenticator_metadata.is_empty()
1191 }
1192}
1193
1194#[derive(Debug, Clone, Serialize, Deserialize)]
1196pub struct AuthenticatorMetadataV1 {
1197 pub function_name: String,
1198 pub account_type: TypeName,
1199}