sui_rpc_store/reader/
layout.rs1use move_core_types::annotated_value::MoveTypeLayout;
33use move_core_types::language_storage::StructTag;
34use sui_consistent_store::FrameworkSchema;
35use sui_consistent_store::reader::Reader;
36use sui_protocol_config::ProtocolConfig;
37use sui_protocol_config::ProtocolVersion;
38use sui_types::base_types::ObjectID;
39use sui_types::digests::ChainIdentifier;
40use sui_types::digests::CheckpointDigest;
41use sui_types::error::SuiResult;
42use sui_types::full_checkpoint_content::ObjectSet;
43use sui_types::storage::BackingPackageStore;
44use sui_types::storage::ObjectStore;
45use sui_types::storage::OverlayBackingPackageStore;
46use sui_types::storage::PackageObject;
47use sui_types::storage::error::Error as StorageError;
48use sui_types::storage::error::Result as StorageResult;
49use sui_types::sui_system_state::SuiSystemStateTrait;
50
51use crate::RpcStoreSchema;
52use crate::reader::RpcStoreReader;
53
54impl<R: Reader + Send + Sync> RpcStoreReader<R> {
55 pub fn resolve_struct_layout(
63 &self,
64 struct_tag: &StructTag,
65 overlay: &ObjectSet,
66 ) -> StorageResult<Option<MoveTypeLayout>> {
67 let Some(protocol_config) = self.live_protocol_config()? else {
68 return Ok(None);
69 };
70
71 let executor = sui_execution::executor(&protocol_config, true)
72 .map_err(StorageError::custom)?;
73
74 let backing = PackageStoreOverObjects {
75 schema: self.schema(),
76 };
77 let overlay_store = OverlayBackingPackageStore::new(overlay, &backing);
78
79 let layout = executor
80 .type_layout_resolver(&protocol_config, Box::new(overlay_store))
81 .get_annotated_layout(struct_tag)
82 .map_err(StorageError::custom)?;
83 Ok(Some(layout.into_layout()))
84 }
85
86 fn live_protocol_config(&self) -> StorageResult<Option<ProtocolConfig>> {
93 let Some(chain) = self.read_chain_identifier()? else {
94 return Ok(None);
95 };
96 let Some(protocol_version) = self.latest_protocol_version()? else {
97 return Ok(None);
98 };
99 Ok(ProtocolConfig::get_for_version_if_supported(
100 protocol_version,
101 chain.chain(),
102 ))
103 }
104
105 fn read_chain_identifier(&self) -> StorageResult<Option<ChainIdentifier>> {
109 let framework = FrameworkSchema::new(self.db().clone());
110 let first = framework
111 .chain_ids
112 .iter(..)
113 .map_err(StorageError::custom)?
114 .next();
115 let Some(entry) = first else {
116 return Ok(None);
117 };
118 let (_, chain_id) = entry.map_err(StorageError::custom)?;
119 Ok(Some(ChainIdentifier::from(CheckpointDigest::new(
120 chain_id.0,
121 ))))
122 }
123
124 fn latest_protocol_version(&self) -> StorageResult<Option<ProtocolVersion>> {
127 let epochs = &self.schema().epochs;
128 let latest = epochs.iter_rev(..).map_err(StorageError::custom)?.next();
129 let Some(entry) = latest else {
130 return Ok(None);
131 };
132 let (epoch_id, _) = entry.map_err(StorageError::custom)?;
133 let Some(info) = self
134 .schema()
135 .get_epoch(epoch_id.0)
136 .map_err(StorageError::custom)?
137 else {
138 return Ok(None);
139 };
140 let Some(state) = info.system_state else {
141 return Ok(None);
142 };
143 Ok(Some(ProtocolVersion::new(state.protocol_version())))
144 }
145}
146
147struct PackageStoreOverObjects<'a, R: Reader> {
153 schema: &'a RpcStoreSchema<R>,
154}
155
156impl<R: Reader> BackingPackageStore for PackageStoreOverObjects<'_, R> {
157 fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObject>> {
158 let Some(object) = ObjectStore::get_object(&self.schema_object_store(), package_id) else {
159 return Ok(None);
160 };
161 if !object.is_package() {
162 return Ok(None);
163 }
164 Ok(Some(PackageObject::new(object)))
165 }
166}
167
168impl<R: Reader> PackageStoreOverObjects<'_, R> {
169 fn schema_object_store(&self) -> SchemaObjectStore<'_, R> {
175 SchemaObjectStore {
176 schema: self.schema,
177 }
178 }
179}
180
181struct SchemaObjectStore<'a, R: Reader> {
182 schema: &'a RpcStoreSchema<R>,
183}
184
185impl<R: Reader> ObjectStore for SchemaObjectStore<'_, R> {
186 fn get_object(&self, object_id: &ObjectID) -> Option<sui_types::object::Object> {
187 self.schema.get_object(*object_id).ok().flatten()
188 }
189
190 fn get_object_by_key(
191 &self,
192 object_id: &ObjectID,
193 version: sui_types::base_types::VersionNumber,
194 ) -> Option<sui_types::object::Object> {
195 self.schema
196 .get_object_by_key(*object_id, version)
197 .ok()
198 .flatten()
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use std::sync::Arc;
205
206 use sui_consistent_store::Db;
207 use sui_consistent_store::DbOptions;
208 use sui_types::full_checkpoint_content::ObjectSet;
209
210 use super::*;
211 use crate::reader::RpcStoreReader;
212
213 #[test]
218 fn resolve_returns_none_when_no_chain_id_or_epoch() {
219 let dir = tempfile::tempdir().unwrap();
220 let (db, schema) = Db::open::<RpcStoreSchema>(dir.path(), DbOptions::default()).unwrap();
221 let reader = RpcStoreReader::new(db, Arc::new(schema));
222
223 let tag = StructTag {
224 address: move_core_types::account_address::AccountAddress::new([1u8; 32]),
225 module: move_core_types::identifier::Identifier::new("foo").unwrap(),
226 name: move_core_types::identifier::Identifier::new("Bar").unwrap(),
227 type_params: vec![],
228 };
229 let overlay = ObjectSet::default();
230 assert!(
231 reader
232 .resolve_struct_layout(&tag, &overlay)
233 .unwrap()
234 .is_none()
235 );
236 }
237}