sui_adapter_v3/data_store/legacy/
linkage_view.rs1use crate::data_store::PackageStore;
5use move_core_types::{
6 account_address::AccountAddress,
7 identifier::{IdentStr, Identifier},
8 language_storage::ModuleId,
9 resolver::ModuleResolver,
10};
11use move_vm_types::data_store::LinkageResolver;
12use std::{
13 cell::RefCell,
14 collections::{BTreeMap, HashMap, HashSet, hash_map::Entry},
15 rc::Rc,
16 str::FromStr,
17};
18use sui_types::{
19 base_types::ObjectID,
20 error::{ExecutionError, SuiError, SuiResult},
21 move_package::{MovePackage, TypeOrigin, UpgradeInfo},
22};
23
24pub struct LinkageView<'state> {
27 resolver: Box<dyn PackageStore + 'state>,
30 linkage_info: RefCell<Option<LinkageInfo>>,
32 type_origin_cache: RefCell<HashMap<ModuleId, HashMap<Identifier, AccountAddress>>>,
40 past_contexts: RefCell<HashSet<ObjectID>>,
43}
44
45#[derive(Debug)]
46pub struct LinkageInfo {
47 storage_id: AccountAddress,
48 runtime_id: AccountAddress,
49 link_table: BTreeMap<ObjectID, UpgradeInfo>,
50}
51
52pub struct SavedLinkage(LinkageInfo);
53
54impl<'state> LinkageView<'state> {
55 pub fn new(resolver: Box<dyn PackageStore + 'state>) -> Self {
56 Self {
57 resolver,
58 linkage_info: RefCell::new(None),
59 type_origin_cache: RefCell::new(HashMap::new()),
60 past_contexts: RefCell::new(HashSet::new()),
61 }
62 }
63
64 pub fn reset_linkage(&self) -> Result<(), ExecutionError> {
65 let Ok(mut linkage_info) = self.linkage_info.try_borrow_mut() else {
66 invariant_violation!("Unable to reset linkage")
67 };
68 *linkage_info = None;
69 Ok(())
70 }
71
72 pub fn has_linkage(&self, context: ObjectID) -> Result<bool, ExecutionError> {
75 let Ok(linkage_info) = self.linkage_info.try_borrow() else {
76 invariant_violation!("Unable to borrow linkage info")
77 };
78 Ok(linkage_info
79 .as_ref()
80 .is_some_and(|l| l.storage_id == *context))
81 }
82
83 pub fn steal_linkage(&self) -> Option<SavedLinkage> {
85 Some(SavedLinkage(self.linkage_info.take()?))
86 }
87
88 pub fn restore_linkage(&self, saved: Option<SavedLinkage>) -> Result<(), ExecutionError> {
90 let Some(SavedLinkage(saved)) = saved else {
91 return Ok(());
92 };
93
94 let Ok(mut linkage_info) = self.linkage_info.try_borrow_mut() else {
95 invariant_violation!("Unable to borrow linkage while restoring")
96 };
97 if let Some(existing) = &*linkage_info {
98 invariant_violation!(
99 "Attempt to overwrite linkage by restoring: {saved:#?} \
100 Existing linkage: {existing:#?}",
101 )
102 }
103
104 *linkage_info = Some(saved);
107 Ok(())
108 }
109
110 pub fn set_linkage(&self, context: &MovePackage) -> Result<AccountAddress, ExecutionError> {
114 let Ok(mut linkage_info) = self.linkage_info.try_borrow_mut() else {
115 invariant_violation!("Unable to borrow linkage to set")
116 };
117 if let Some(existing) = &*linkage_info {
118 invariant_violation!(
119 "Attempt to overwrite linkage info with context from {}. \
120 Existing linkage: {existing:#?}",
121 context.id(),
122 )
123 }
124
125 let linkage = LinkageInfo::from(context);
126 let storage_id = context.id();
127 let runtime_id = linkage.runtime_id;
128 *linkage_info = Some(linkage);
129
130 if !self.past_contexts.borrow_mut().insert(storage_id) {
131 return Ok(runtime_id);
132 }
133
134 for TypeOrigin {
138 module_name,
139 datatype_name: struct_name,
140 package: defining_id,
141 } in context.type_origin_table()
142 {
143 let Ok(module_name) = Identifier::from_str(module_name) else {
144 invariant_violation!("Module name isn't an identifier: {module_name}");
145 };
146
147 let Ok(struct_name) = Identifier::from_str(struct_name) else {
148 invariant_violation!("Struct name isn't an identifier: {struct_name}");
149 };
150
151 let runtime_id = ModuleId::new(runtime_id, module_name);
152 self.add_type_origin(runtime_id, struct_name, *defining_id)?;
153 }
154
155 Ok(runtime_id)
156 }
157
158 pub fn original_package_id(&self) -> Result<Option<AccountAddress>, ExecutionError> {
159 let Ok(linkage_info) = self.linkage_info.try_borrow() else {
160 invariant_violation!("Unable to borrow linkage info")
161 };
162 Ok(linkage_info.as_ref().map(|info| info.runtime_id))
163 }
164
165 fn get_cached_type_origin(
166 &self,
167 runtime_id: &ModuleId,
168 struct_: &IdentStr,
169 ) -> Option<AccountAddress> {
170 self.type_origin_cache
171 .borrow()
172 .get(runtime_id)?
173 .get(struct_)
174 .cloned()
175 }
176
177 fn add_type_origin(
178 &self,
179 runtime_id: ModuleId,
180 struct_: Identifier,
181 defining_id: ObjectID,
182 ) -> Result<(), ExecutionError> {
183 let mut cache = self.type_origin_cache.borrow_mut();
184 let module_cache = cache.entry(runtime_id.clone()).or_default();
185
186 match module_cache.entry(struct_) {
187 Entry::Vacant(entry) => {
188 entry.insert(*defining_id);
189 }
190
191 Entry::Occupied(entry) => {
192 if entry.get() != &*defining_id {
193 invariant_violation!(
194 "Conflicting defining ID for {}::{}: {} and {}",
195 runtime_id,
196 entry.key(),
197 defining_id,
198 entry.get(),
199 );
200 }
201 }
202 }
203
204 Ok(())
205 }
206
207 pub(crate) fn link_context(&self) -> Result<AccountAddress, ExecutionError> {
208 let Ok(linkage_info) = self.linkage_info.try_borrow() else {
209 invariant_violation!("Unable to borrow linkage info")
210 };
211 Ok(linkage_info
212 .as_ref()
213 .map_or(AccountAddress::ZERO, |l| l.storage_id))
214 }
215
216 pub(crate) fn relocate(&self, module_id: &ModuleId) -> Result<ModuleId, SuiError> {
217 let Ok(linkage_info) = self.linkage_info.try_borrow() else {
218 invariant_violation!("Unable to borrow linkage info")
219 };
220 let Some(linkage) = &*linkage_info else {
221 invariant_violation!("No linkage context set while relocating {module_id}.")
222 };
223
224 if module_id.address() == &linkage.runtime_id {
227 return Ok(ModuleId::new(
228 linkage.storage_id,
229 module_id.name().to_owned(),
230 ));
231 }
232
233 let runtime_id = ObjectID::from_address(*module_id.address());
234 let Some(upgrade) = linkage.link_table.get(&runtime_id) else {
235 invariant_violation!(
236 "Missing linkage for {runtime_id} in context {}, runtime_id is {}",
237 linkage.storage_id,
238 linkage.runtime_id
239 );
240 };
241
242 Ok(ModuleId::new(
243 upgrade.upgraded_id.into(),
244 module_id.name().to_owned(),
245 ))
246 }
247
248 pub(crate) fn defining_module(
249 &self,
250 runtime_id: &ModuleId,
251 struct_: &IdentStr,
252 ) -> Result<ModuleId, SuiError> {
253 let Ok(linkage_info) = self.linkage_info.try_borrow() else {
254 invariant_violation!("Unable to borrow linkage info")
255 };
256 if linkage_info.is_none() {
257 invariant_violation!(
258 "No linkage context set for defining module query on {runtime_id}::{struct_}."
259 )
260 }
261
262 if let Some(cached) = self.get_cached_type_origin(runtime_id, struct_) {
263 return Ok(ModuleId::new(cached, runtime_id.name().to_owned()));
264 }
265
266 let storage_id = ObjectID::from(*self.relocate(runtime_id)?.address());
267 let Some(package) = self.resolver.get_package(&storage_id)? else {
268 invariant_violation!("Missing dependent package in store: {storage_id}",)
269 };
270
271 for TypeOrigin {
272 module_name,
273 datatype_name: struct_name,
274 package,
275 } in package.type_origin_table()
276 {
277 if module_name == runtime_id.name().as_str() && struct_name == struct_.as_str() {
278 self.add_type_origin(runtime_id.clone(), struct_.to_owned(), *package)?;
279 return Ok(ModuleId::new(**package, runtime_id.name().to_owned()));
280 }
281 }
282
283 invariant_violation!(
284 "{runtime_id}::{struct_} not found in type origin table in {storage_id} (v{})",
285 package.version(),
286 )
287 }
288}
289
290impl From<&MovePackage> for LinkageInfo {
291 fn from(package: &MovePackage) -> Self {
292 Self {
293 storage_id: package.id().into(),
294 runtime_id: package.original_package_id().into(),
295 link_table: package.linkage_table().clone(),
296 }
297 }
298}
299
300impl LinkageResolver for LinkageView<'_> {
301 type Error = SuiError;
302
303 fn link_context(&self) -> AccountAddress {
304 LinkageView::link_context(self).unwrap()
306 }
307
308 fn relocate(&self, module_id: &ModuleId) -> Result<ModuleId, Self::Error> {
309 LinkageView::relocate(self, module_id)
310 }
311
312 fn defining_module(
313 &self,
314 runtime_id: &ModuleId,
315 struct_: &IdentStr,
316 ) -> Result<ModuleId, Self::Error> {
317 LinkageView::defining_module(self, runtime_id, struct_)
318 }
319}
320
321impl ModuleResolver for LinkageView<'_> {
322 type Error = SuiError;
323
324 fn get_module(&self, id: &ModuleId) -> Result<Option<Vec<u8>>, Self::Error> {
325 Ok(self
326 .get_package(&ObjectID::from(*id.address()))?
327 .and_then(|package| {
328 package
329 .serialized_module_map()
330 .get(id.name().as_str())
331 .cloned()
332 }))
333 }
334
335 fn get_packages_static<const N: usize>(
336 &self,
337 _ids: [AccountAddress; N],
338 ) -> Result<[Option<move_core_types::resolver::SerializedPackage>; N], Self::Error> {
339 unreachable!("v3 get_packages_static should not be called on LinkageView")
340 }
341
342 fn get_packages<'a>(
343 &self,
344 _ids: impl ExactSizeIterator<Item = &'a AccountAddress>,
345 ) -> Result<Vec<Option<move_core_types::resolver::SerializedPackage>>, Self::Error> {
346 unreachable!("v3 get_packages should not be called on LinkageView")
347 }
348}
349
350impl PackageStore for LinkageView<'_> {
351 fn get_package(&self, package_id: &ObjectID) -> SuiResult<Option<Rc<MovePackage>>> {
352 self.resolver.get_package(package_id)
353 }
354
355 fn resolve_type_to_defining_id(
356 &self,
357 _module_address: ObjectID,
358 _module_name: &IdentStr,
359 _type_name: &IdentStr,
360 ) -> SuiResult<Option<ObjectID>> {
361 unimplemented!(
362 "resolve_type_to_defining_id is not implemented for LinkageView and should never be called"
363 )
364 }
365}