iota_types/
move_package.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5//! Move package.
6//!
7//! This module contains the [MovePackage] and types necessary for describing
8//! its update behavior and linkage information for module resolution during
9//! execution.
10//!
11//! Upgradeable packages form a version chain. This is simply the conceptual
12//! chain of package versions, with their monotonically increasing version
13//! numbers. Package { version: 1 } => Package { version: 2 } => ...
14//!
15//! The code contains terminology that may be confusing for the uninitiated,
16//! like `Module ID`, `Package ID`, `Storage ID` and `Runtime ID`. For avoidance
17//! of doubt these concepts are defined like so:
18//! - `Package ID` is the [ObjectID] representing the address by which the given
19//!   package may be found in storage.
20//! - `Runtime ID` will always mean the `Package ID`/`Storage ID` of the
21//!   initially published package. For a non upgradeable package this will
22//!   always be equal to `Storage ID`. For an upgradeable package, it will be
23//!   the `Storage ID` of the package's first deployed version.
24//! - `Storage ID` is the `Package ID`, and it is mostly used in to highlight
25//!   that we are talking about the current `Package ID` and not the `Runtime
26//!   ID`
27//! - `Module ID` is the the type
28//!   [ModuleID](move_core_types::language_storage::ModuleId).
29//!
30//! Some of these are redundant and have overlapping meaning, so whenever
31//! reasonable/necessary the possible naming will be listed. From all of these
32//! `Runtime ID` and `Module ID` are the most confusing. `Module ID` may be used
33//! with `Runtime ID` and `Storage ID` depending on the context. While `Runtime
34//! ID` is mostly used in name resolution during runtime, when a package with
35//! its modules has been loaded.
36use 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)]
81/// Additional information about a function
82pub struct FnInfo {
83    /// If true, it's a function involved in testing (`[test]`, `[test_only]`,
84    /// `[expected_failure]`)
85    pub is_test: bool,
86    /// If set, function was marked to represent authenticator function of
87    /// given version.
88    pub authenticator_version: Option<u8>,
89}
90
91#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
92/// Uniquely identifies a function in a module
93pub struct FnInfoKey {
94    pub fn_name: String,
95    pub mod_name: String,
96    pub mod_addr: AccountAddress,
97}
98
99/// A map from function info keys to function info
100pub type FnInfoMap = BTreeMap<FnInfoKey, FnInfo>;
101
102/// Store the origin of a data type where it first appeared in the version
103/// chain.
104///
105/// A data type is identified by the name of the module and the name of the
106/// struct/enum in combination.
107///
108/// # Undefined behavior
109///
110/// Directly modifying any field is undefined behavior. The fields are only
111/// public for read-only access.
112#[derive(
113    Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, Hash, JsonSchema,
114)]
115pub struct TypeOrigin {
116    /// The name of the module the data type resides in.
117    pub module_name: String,
118    /// The name of the data type.
119    ///
120    /// Here this either refers to an enum or a struct identifier.
121    // `struct_name` alias to support backwards compatibility with the old name
122    #[serde(alias = "struct_name")]
123    pub datatype_name: String,
124    /// `Storage ID` of the package, where the given type first appeared.
125    pub package: ObjectID,
126}
127
128/// Value for the [MovePackage]'s linkage_table.
129///
130/// # Undefined behavior
131///
132/// Directly modifying any field is undefined behavior. The fields are only
133/// public for read-only access.
134#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash, JsonSchema)]
135pub struct UpgradeInfo {
136    /// `Storage ID`/`Package ID` of the referred package.
137    pub upgraded_id: ObjectID,
138    /// The version of the package at `upgraded_id`.
139    pub upgraded_version: SequenceNumber,
140}
141
142// serde_bytes::ByteBuf is an analog of Vec<u8> with built-in fast
143// serialization.
144#[serde_as]
145#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)]
146pub struct MovePackage {
147    /// The `Storage ID` of the package.
148    pub(crate) id: ObjectID,
149    /// Most move packages are uniquely identified by their ID (i.e. there is
150    /// only one version per ID), but the version is still stored because
151    /// one package may be an upgrade of another (at a different ID), in
152    /// which case its version will be one greater than the version of the
153    /// upgraded package.
154    ///
155    /// Framework packages are an exception to this rule -- all versions of the
156    /// framework packages exist at the same ID, at increasing versions.
157    ///
158    /// In all cases, packages are referred to by move calls using just their
159    /// ID, and they are always loaded at their latest version.
160    pub(crate) version: SequenceNumber,
161    /// Map module identifiers to their serialized [CompiledModule].
162    ///
163    /// All modules within a package share the `Storage ID` of their containing
164    /// package.
165    #[serde_as(as = "BTreeMap<_, Bytes>")]
166    pub(crate) module_map: BTreeMap<String, Vec<u8>>,
167
168    /// Maps structs and enums in a given module to a package version where they
169    /// were first defined.
170    ///  
171    /// Stored as a vector for simple serialization and
172    /// deserialization.
173    pub(crate) type_origin_table: Vec<TypeOrigin>,
174
175    /// For each dependency, it maps the `Runtime ID` (the first package's
176    /// `Storage ID` in a version chain) of the containing package to the
177    /// `UpgradeInfo` containing the actually used version.
178    pub(crate) linkage_table: BTreeMap<ObjectID, UpgradeInfo>,
179}
180
181// NB: do _not_ add `Serialize` or `Deserialize` to this enum. Convert to u8
182// first  or use the associated constants before storing in any serialization
183// setting.
184/// Rust representation of upgrade policy constants in `iota::package`.
185#[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    /// Convenience accessors to the upgrade policies as u8s.
198    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/// Rust representation of `iota::package::UpgradeCap`.
220#[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/// Rust representation of `iota::package::UpgradeTicket`.
229#[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/// Rust representation of `iota::package::UpgradeReceipt`.
238#[derive(Debug, Serialize, Deserialize)]
239pub struct UpgradeReceipt {
240    pub cap: ID,
241    pub package: ID,
242}
243
244impl MovePackage {
245    /// Create a package with all required data (including serialized modules,
246    /// type origin and linkage tables) already supplied.
247    ///
248    /// It does not perform any type of validation. Ensure that the supplied
249    /// parts are semantically valid.
250    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    /// Calculate the digest of the [MovePackage].
277    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    /// It is important that this function is shared across both the calculation
287    /// of the digest for the package, and the calculation of the digest
288    /// on-chain.
289    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        // NB: sorting so the order of the modules and the order of the dependencies
304        // does not matter.
305        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    /// Create an initial version of the package along with this version's type
315    /// origin and linkage tables.
316    ///
317    /// # Undefined behavior
318    ///
319    /// All passed modules must have the same `Runtime ID` or the behavior is
320    /// undefined.
321    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    /// Create an upgraded version of the package along with this version's type
344    /// origin and linkage tables.
345    ///
346    /// # Undefined behavior
347    ///
348    /// All passed modules must have the same `Runtime ID` or the behavior is
349    /// undefined.
350    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                // The upgraded version is used by other packages that transitively depend on this
391                // system package, to make sure that if they choose a different version to depend on
392                // compared to their dependencies, they pick a greater version.
393                //
394                // However, in the case of system packages, although they can be upgraded, unlike
395                // other packages, only one version can be in use on the network at any given time,
396                // so it is not possible for a package to require a different system package version
397                // compared to its dependencies.
398                //
399                // This reason, coupled with the fact that system packages can only depend on each
400                // other, mean that their own linkage tables always report a version of zero.
401                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, // System packages are not subject to the size limit
420            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    /// Retrieve the module from this package with the given [ModuleId].
475    ///
476    /// [ModuleId] is expected to contain the `Storage ID` of this package.
477    /// In case the `Storage ID` doesn't match or the module name is not
478    /// present in this package the function returns None.
479    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    /// Return the size of the package in bytes
488    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                    // SequenceNumber
511                ));
512
513        8 /* SequenceNumber */ + module_map_size + type_origin_table_size + linkage_table_size
514    }
515
516    /// `Package ID`/`Storage ID` of this package.
517    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    /// Approximate size of the package in bytes. This is used for gas metering.
534    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    /// The `Package ID` of the first version of this package.
564    ///
565    /// Also referred to as `Runtime ID`.
566    ///
567    /// Regardless of which version of the package we are working with, this
568    /// function will always return the `Package ID`/`Storage ID` of the first
569    /// package version in the version chain.
570    pub fn original_package_id(&self) -> ObjectID {
571        if self.version == OBJECT_START_VERSION {
572            // for a non-upgraded package, original ID is just the package ID
573            return self.id;
574        }
575
576        let bytes = self.module_map.values().next().expect("Empty module map");
577        // Remember, that all modules will contain the `Package ID` of the first
578        // deployed package. This is why taking any of them will produce the
579        // original package id.
580        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        // TODO use the session's cache
591        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    /// If `include_code` is set to `false`, the normalized module will skip
604    /// function bodies but still include the signatures.
605    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    /// Create an `UpgradeCap` for the newly published package at `package_id`,
626    /// and associate it with the fresh `uid`.
627    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    /// Create an `UpgradeReceipt` for the upgraded package at `package_id`
659    /// using the `UpgradeTicket` and newly published package id.
660    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
668/// Checks if a function is annotated with one of the test-related annotations
669pub 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
708/// If `include_code` is set to `false`, the normalized module will skip
709/// function bodies but still include the signatures.
710pub 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
738/// If `include_code` is set to `false`, the normalized module will skip
739/// function bodies but still include the signatures.
740pub 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        // original_package_id will deserialize a module but only for the purpose of
771        // obtaining "original ID" of the package containing it so using max
772        // Move binary version during deserialization is OK
773        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                // Found an immediate dependency, mark it as seen, and stash a reference to its
794                // linkage table to check later.
795                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    // (1) Every dependency is represented in the transitive dependencies
807    if !immediate_dependencies.is_empty() {
808        return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into());
809    }
810
811    // (2) Every dependency's linkage table is superseded by this linkage table
812    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            // if id exists in the predecessor's table, use it, otherwise use the id of the
873            // upgraded module
874            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            // if id exists in the predecessor's table, use it, otherwise use the id of the
888            // upgraded module
889            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/// IOTA specific metadata attached to the metadata section of file_format.
910#[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        // Safe unwrap as the RuntimeModuleMetadataWrapper struct is always serializable
921        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/// IOTA specific metadata attached to the metadata section of file_format.
937#[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/// The list of iota attribute types recognized by the compiler.
997#[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/// V1 of IOTA specific metadata.
1014#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1015pub struct RuntimeModuleMetadataV1 {
1016    /// Attributes attached to functions, by definition index.
1017    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        // Safe unwrap as the RuntimeModuleMetadataV1 struct is always serializable
1034        bcs::to_bytes(&self).unwrap()
1035    }
1036}
1037
1038/// Enum for handling the PackageMetadata framework type. The PackageMetadata is
1039/// IOTA specific metadata derived from a package and readable on-chain. This
1040/// enums helps with the versioning, which is actually used as the object
1041/// content, i.e., PackageMetadataV1 is the type used on-chain.
1042#[derive(Debug, Clone, Serialize, Deserialize)]
1043pub enum PackageMetadata {
1044    V1(PackageMetadataV1),
1045}
1046
1047impl PackageMetadata {
1048    /// Create a `PackageMetadata` for the newly
1049    /// published/upgraded package at `package_id`
1050    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    // This field is required to make a Rust struct compatible with an empty Move one.
1082    // An empty Move struct contains a 1-byte dummy bool field because empty fields are not
1083    // allowed in the bytecode.
1084    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        // Safe unwrap as the PackageMetadataKey struct is always serializable
1099        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() // safe because type tag is known
1110}
1111
1112/// V1 of IOTA specific package metadata.
1113#[derive(Debug, Clone, Serialize, Deserialize)]
1114pub struct PackageMetadataV1 {
1115    // The package metadata object UID
1116    pub uid: UID,
1117    /// Storage ID of the package represented by this metadata
1118    /// The object id of the runtime package metadata object is derived from
1119    /// this value.
1120    pub storage_id: ID,
1121    /// Runtime ID of the package represented by this metadata. Runtime ID is
1122    /// the Storage ID of the first version of a package.
1123    pub runtime_id: ID,
1124    /// Version of the package represented by this metadata
1125    pub package_version: u64,
1126    // Handles to internal package modules
1127    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        // Safe unwrap as the PackageMetadataV1 struct is always serializable
1178        bcs::to_bytes(&self).unwrap()
1179    }
1180}
1181
1182/// V1 of IOTA specific module metadata. Only includes authenticator info.
1183#[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/// V1 of IOTA specific authenticator info metadata.
1195#[derive(Debug, Clone, Serialize, Deserialize)]
1196pub struct AuthenticatorMetadataV1 {
1197    pub function_name: String,
1198    pub account_type: TypeName,
1199}