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