sui_adapter_latest/data_store/
cached_package_store.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::data_store::{PackageStore, transaction_package_store::TransactionPackageStore};
5use move_core_types::{identifier::IdentStr, resolver::IntraPackageName};
6use move_vm_runtime::{
7    cache::move_cache::ResolvedPackageResult, runtime::MoveRuntime,
8    validation::verification::ast::Package as VerifiedPackage,
9};
10use std::{rc::Rc, sync::Arc};
11use sui_types::{
12    base_types::ObjectID,
13    error::{ExecutionError, SuiErrorKind, SuiResult},
14    execution_status::ExecutionErrorKind,
15    move_package::MovePackage,
16};
17
18/// The `CachedPackageStore` is a `PackageStore` implementation that uses a `MoveRuntime` to
19/// fetch and cache packages. It also uses an underlying `TransactionPackageStore` to fetch packages
20/// that are not in the cache. This is used to provide package loading (from storage)
21/// for the Move VM, while also allowing for packages that are being published in the
22/// current transaction to be found.
23pub struct CachedPackageStore<'state, 'runtime> {
24    /// The Move runtime to use for fetching and caching packages.
25    runtime: &'runtime MoveRuntime,
26
27    /// Underlying store to fetch packages from. Any newly published packages in the current
28    /// transaction should be in the `new_packages` field of this store.
29    pub package_store: TransactionPackageStore<'state>,
30}
31
32impl<'state, 'runtime> CachedPackageStore<'state, 'runtime> {
33    pub fn new(
34        runtime: &'runtime MoveRuntime,
35        package_store: TransactionPackageStore<'state>,
36    ) -> Self {
37        Self {
38            runtime,
39            package_store,
40        }
41    }
42
43    /// Get a package by its package ID (i.e., not original ID). This will first look in the new
44    /// packages, and then fetch the pacakge from the underlying Move runtime which handles loading
45    /// and caching of packages. If the package is not found, None is returned. If there is an error
46    /// fetching the package, an error is returned.
47    ///
48    /// Once the package is fetched it is in the Move runtime cache, and will be found there on
49    /// subsequent lookups.
50    pub fn get_package(&self, object_id: &ObjectID) -> SuiResult<Option<Arc<VerifiedPackage>>> {
51        self.fetch_package(object_id)
52    }
53
54    pub fn get_move_package(&self, object_id: &ObjectID) -> SuiResult<Option<Rc<MovePackage>>> {
55        self.package_store.fetch_move_package(**object_id)
56    }
57
58    /// Get a package by its package ID (i.e., not original ID). This will first look in the new
59    /// packages, and then fetch the pacakge from the underlying Move runtime which handles loading
60    /// and caching of packages.
61    fn fetch_package(&self, id: &ObjectID) -> SuiResult<Option<Arc<VerifiedPackage>>> {
62        // Look for package in new packages first. If we have just published the package we are
63        // looking up it may not be in the VM runtime cache yet, and we don't want to add it to the
64        // cache either. So if it's in the new packages, we return it directly.
65        if let Some((_move_pkg, verified_pkg)) = self.package_store.fetch_new_package(id) {
66            return Ok(Some(verified_pkg));
67        }
68
69        // load the package via the Move runtime, which will cache it if found.
70        match self
71            .runtime
72            .resolve_and_cache_package(&self.package_store, (*id).into())
73            .map_err(|e| {
74                SuiErrorKind::ExecutionError(
75                    ExecutionError::new_with_source(
76                        ExecutionErrorKind::VMVerificationOrDeserializationError,
77                        e.to_string(),
78                    )
79                    .to_string(),
80                )
81            })? {
82            ResolvedPackageResult::Found(pkg) => Ok(Some(pkg.verified.clone())),
83            ResolvedPackageResult::NotFound => Ok(None),
84        }
85    }
86}
87
88impl PackageStore for CachedPackageStore<'_, '_> {
89    fn get_package(&self, id: &ObjectID) -> SuiResult<Option<Arc<VerifiedPackage>>> {
90        self.get_package(id)
91    }
92
93    fn resolve_type_to_defining_id(
94        &self,
95        module_address: ObjectID,
96        module_name: &IdentStr,
97        type_name: &IdentStr,
98    ) -> SuiResult<Option<ObjectID>> {
99        let Some(pkg) = self.get_package(&module_address)? else {
100            return Ok(None);
101        };
102
103        Ok(pkg
104            .type_origin_table()
105            .get(&IntraPackageName {
106                module_name: module_name.to_owned(),
107                type_name: type_name.to_owned(),
108            })
109            .map(|id| ObjectID::from(*id)))
110    }
111}