sui_adapter_v3/data_store/
linked_data_store.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::resolved_linkage::RootedLinkage,
7};
8use move_binary_format::errors::{Location, PartialVMError, PartialVMResult, VMResult};
9use move_core_types::{
10    account_address::AccountAddress, identifier::IdentStr, language_storage::ModuleId,
11    resolver::ModuleResolver, vm_status::StatusCode,
12};
13use move_vm_types::data_store::{DataStore, LinkageResolver};
14use sui_types::{base_types::ObjectID, error::SuiError, execution_status::ExecutionErrorKind};
15
16/// A `LinkedDataStore` is a wrapper around a `PackageStore` (i.e., a package store where
17/// we can also resolve types to defining IDs) along with a specific `linkage`. These two together
18/// allow us to resolve modules and types in a way that is consistent with the `linkage` provided
19/// and allow us to then pass this into the VM. Until we have a linkage set it is not possible to
20/// construct a valid `DataStore` for execution in the VM as it needs to be able to resolve modules
21/// under a specific linkage.
22pub struct LinkedDataStore<'a> {
23    pub linkage: &'a RootedLinkage,
24    pub store: &'a dyn PackageStore,
25}
26
27impl<'a> LinkedDataStore<'a> {
28    pub fn new(linkage: &'a RootedLinkage, store: &'a dyn PackageStore) -> Self {
29        Self { linkage, store }
30    }
31}
32
33impl DataStore for LinkedDataStore<'_> {
34    fn link_context(&self) -> PartialVMResult<AccountAddress> {
35        Ok(self.linkage.link_context)
36    }
37
38    fn relocate(&self, module_id: &ModuleId) -> PartialVMResult<ModuleId> {
39        self.linkage
40            .resolved_linkage
41            .linkage
42            .get(&ObjectID::from(*module_id.address()))
43            .map(|obj_id| ModuleId::new(**obj_id, module_id.name().to_owned()))
44            .ok_or_else(|| {
45                PartialVMError::new(StatusCode::LINKER_ERROR).with_message(format!(
46                    "Error relocating {module_id} -- could not find linkage"
47                ))
48            })
49    }
50
51    fn defining_module(
52        &self,
53        module_id: &ModuleId,
54        struct_: &IdentStr,
55    ) -> PartialVMResult<ModuleId> {
56        self.store
57            .resolve_type_to_defining_id(
58                    ObjectID::from(*module_id.address()),
59                    module_id.name(),
60                    struct_,
61                )
62                .ok()
63                .flatten()
64                .map(|obj_id| ModuleId::new(*obj_id, module_id.name().to_owned()))
65                .ok_or_else(|| {
66                    PartialVMError::new(StatusCode::LINKER_ERROR).with_message(format!(
67                        "Error finding defining module for {module_id}::{struct_} -- could nod find linkage"
68                    ))
69                })
70    }
71
72    // NB: module_id is original ID based
73    fn load_module(&self, module_id: &ModuleId) -> VMResult<Vec<u8>> {
74        let package_storage_id = ObjectID::from(*module_id.address());
75        match self
76            .store
77            .get_package(&package_storage_id)
78            .map(|pkg| pkg.and_then(|pkg| pkg.get_module(module_id).cloned()))
79        {
80            Ok(Some(bytes)) => Ok(bytes),
81            Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
82                .with_message(format!("Cannot find {:?} in data cache", module_id))
83                .finish(Location::Undefined)),
84            Err(err) => {
85                let msg = format!("Unexpected storage error: {:?}", err);
86                Err(
87                    PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
88                        .with_message(msg)
89                        .finish(Location::Undefined),
90                )
91            }
92        }
93    }
94
95    fn publish_module(&mut self, _module_id: &ModuleId, _blob: Vec<u8>) -> VMResult<()> {
96        Ok(())
97    }
98}
99
100impl DataStore for &LinkedDataStore<'_> {
101    fn link_context(&self) -> PartialVMResult<AccountAddress> {
102        DataStore::link_context(*self)
103    }
104
105    fn relocate(&self, module_id: &ModuleId) -> PartialVMResult<ModuleId> {
106        DataStore::relocate(*self, module_id)
107    }
108
109    fn defining_module(
110        &self,
111        module_id: &ModuleId,
112        struct_: &IdentStr,
113    ) -> PartialVMResult<ModuleId> {
114        DataStore::defining_module(*self, module_id, struct_)
115    }
116
117    fn load_module(&self, module_id: &ModuleId) -> VMResult<Vec<u8>> {
118        DataStore::load_module(*self, module_id)
119    }
120
121    fn publish_module(&mut self, _module_id: &ModuleId, _blob: Vec<u8>) -> VMResult<()> {
122        Ok(())
123    }
124}
125
126impl ModuleResolver for LinkedDataStore<'_> {
127    type Error = SuiError;
128
129    fn get_module(&self, id: &ModuleId) -> Result<Option<Vec<u8>>, Self::Error> {
130        self.load_module(id)
131            .map(Some)
132            .map_err(|_| SuiError::from(ExecutionErrorKind::VMVerificationOrDeserializationError))
133    }
134
135    fn get_packages_static<const N: usize>(
136        &self,
137        _ids: [AccountAddress; N],
138    ) -> Result<[Option<move_core_types::resolver::SerializedPackage>; N], Self::Error> {
139        unreachable!("v3 get_packages_static should not be called on LinkedDataStore")
140    }
141
142    fn get_packages<'a>(
143        &self,
144        _ids: impl ExactSizeIterator<Item = &'a AccountAddress>,
145    ) -> Result<Vec<Option<move_core_types::resolver::SerializedPackage>>, Self::Error> {
146        unreachable!("v3 get_packages should not be called on LinkedDataStore")
147    }
148}
149
150impl LinkageResolver for LinkedDataStore<'_> {
151    type Error = SuiError;
152
153    fn link_context(&self) -> AccountAddress {
154        // TODO should we propagate the error
155        DataStore::link_context(self).unwrap()
156    }
157
158    fn relocate(&self, module_id: &ModuleId) -> Result<ModuleId, Self::Error> {
159        DataStore::relocate(self, module_id).map_err(|err| {
160            make_invariant_violation!("Error relocating {}: {:?}", module_id, err).into()
161        })
162    }
163
164    fn defining_module(
165        &self,
166        runtime_id: &ModuleId,
167        struct_: &IdentStr,
168    ) -> Result<ModuleId, Self::Error> {
169        DataStore::defining_module(self, runtime_id, struct_).map_err(|err| {
170            make_invariant_violation!(
171                "Error finding defining module for {}::{}: {:?}",
172                runtime_id,
173                struct_,
174                err
175            )
176            .into()
177        })
178    }
179}