sui_adapter_latest/static_programmable_transactions/linkage/
resolved_linkage.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    data_store::PackageStore,
6    static_programmable_transactions::linkage::resolution::{ResolutionTable, VersionConstraint},
7};
8use move_vm_runtime::shared::linkage_context::LinkageContext;
9use std::{borrow::Borrow, collections::BTreeMap, rc::Rc};
10use sui_types::{base_types::ObjectID, error::ExecutionError};
11
12#[derive(Clone, Debug)]
13pub struct ExecutableLinkage(pub Rc<ResolvedLinkage>);
14
15impl ExecutableLinkage {
16    pub fn new(resolved_linkage: ResolvedLinkage) -> Self {
17        Self(Rc::new(resolved_linkage))
18    }
19
20    /// Given a list of object IDs, generate a `ResolvedLinkage` for them.
21    /// Since this linkage analysis should only be used for types, all packages are resolved
22    /// "upwards" (i.e., later versions of the package are preferred).
23    pub fn type_linkage<I>(ids: I, store: &dyn PackageStore) -> Result<Self, ExecutionError>
24    where
25        I: IntoIterator,
26        I::Item: Borrow<ObjectID>,
27    {
28        let mut resolution_table = ResolutionTable::empty();
29        resolution_table.add_type_linkages_to_table(ids, store)?;
30        Ok(Self::new(ResolvedLinkage::from_resolution_table(
31            resolution_table,
32        )))
33    }
34
35    pub fn linkage_context(&self) -> Result<LinkageContext, ExecutionError> {
36        LinkageContext::new(self.0.linkage.iter().map(|(k, v)| (**k, **v)).collect()).map_err(|e| {
37            make_invariant_violation!(
38                "Failed to create linkage context from resolved linkage: {:?}",
39                e
40            )
41        })
42    }
43}
44
45#[derive(Debug)]
46pub struct ResolvedLinkage {
47    // A mapping of original package ID to its resolved version ID for that linkage.
48    pub linkage: BTreeMap<ObjectID, ObjectID>,
49    // A mapping of every package ID to its runtime ID.
50    // Note: Multiple packages can have the same runtime ID in this mapping, and domain of this map
51    // is a superset of range of `linkage`.
52    pub linkage_resolution: BTreeMap<ObjectID, ObjectID>,
53}
54
55impl ResolvedLinkage {
56    /// In the current linkage resolve an object ID to its original package ID.
57    pub fn resolve_to_original_id(&self, object_id: &ObjectID) -> Option<ObjectID> {
58        self.linkage_resolution.get(object_id).copied()
59    }
60
61    /// Create a `ResolvedLinkage` from a `ResolutionTable`.
62    pub(crate) fn from_resolution_table(resolution_table: ResolutionTable) -> Self {
63        let mut linkage = BTreeMap::new();
64        for (original_id, resolution) in resolution_table.resolution_table {
65            match resolution {
66                VersionConstraint::Exact(_version, object_id)
67                | VersionConstraint::AtLeast(_version, object_id) => {
68                    linkage.insert(original_id, object_id);
69                }
70            }
71        }
72        Self {
73            linkage,
74            linkage_resolution: resolution_table.all_versions_resolution_table,
75        }
76    }
77
78    /// We need to late-bind the "self" resolution since for publication and upgrade we don't know
79    /// this a priori when loading the PTB.
80    pub fn update_for_publication(
81        package_version_id: ObjectID,
82        original_package_id: ObjectID,
83        mut resolved_linkage: ResolvedLinkage,
84    ) -> ExecutableLinkage {
85        // original package ID maps to the link context (new package ID) in this context
86        resolved_linkage
87            .linkage
88            .insert(original_package_id, package_version_id);
89        // Add resolution from the new package ID to the original package ID.
90        resolved_linkage
91            .linkage_resolution
92            .insert(package_version_id, original_package_id);
93        ExecutableLinkage::new(resolved_linkage)
94    }
95}