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