1use std::{fmt::Formatter, sync::LazyLock};
6
7use iota_types::{
8 BRIDGE_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID, IOTA_SYSTEM_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID,
9 STARDUST_PACKAGE_ID,
10 base_types::{ObjectID, ObjectRef},
11 digests::TransactionDigest,
12 move_package::MovePackage,
13 object::{OBJECT_START_VERSION, Object},
14 storage::ObjectStore,
15};
16use move_binary_format::{
17 CompiledModule, binary_config::BinaryConfig, compatibility::Compatibility,
18};
19use move_core_types::gas_algebra::InternalGas;
20use serde::{Deserialize, Serialize};
21use tracing::error;
22
23pub struct SystemPackageMetadata {
25 pub name: String,
27 pub path: String,
30 pub compiled: SystemPackage,
32}
33
34#[derive(Clone, Serialize, PartialEq, Eq, Deserialize)]
37pub struct SystemPackage {
38 pub id: ObjectID,
39 pub bytes: Vec<Vec<u8>>,
40 pub dependencies: Vec<ObjectID>,
41}
42
43impl SystemPackageMetadata {
44 pub fn new(
45 name: impl ToString,
46 path: impl ToString,
47 id: ObjectID,
48 raw_bytes: &'static [u8],
49 dependencies: &[ObjectID],
50 ) -> Self {
51 SystemPackageMetadata {
52 name: name.to_string(),
53 path: path.to_string(),
54 compiled: SystemPackage::new(id, raw_bytes, dependencies),
55 }
56 }
57}
58
59impl SystemPackage {
60 pub fn new(id: ObjectID, raw_bytes: &'static [u8], dependencies: &[ObjectID]) -> Self {
61 let bytes: Vec<Vec<u8>> = bcs::from_bytes(raw_bytes).unwrap();
62 Self {
63 id,
64 bytes,
65 dependencies: dependencies.to_vec(),
66 }
67 }
68
69 pub fn modules(&self) -> Vec<CompiledModule> {
70 self.bytes
71 .iter()
72 .map(|b| CompiledModule::deserialize_with_defaults(b).unwrap())
73 .collect()
74 }
75
76 pub fn genesis_move_package(&self) -> MovePackage {
77 MovePackage::new_system(
78 OBJECT_START_VERSION,
79 &self.modules(),
80 self.dependencies.iter().copied(),
81 )
82 }
83
84 pub fn genesis_object(&self) -> Object {
85 Object::new_system_package(
86 &self.modules(),
87 OBJECT_START_VERSION,
88 self.dependencies.to_vec(),
89 TransactionDigest::genesis_marker(),
90 )
91 }
92}
93
94impl std::fmt::Debug for SystemPackage {
95 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
96 writeln!(f, "Object ID: {:?}", self.id)?;
97 writeln!(f, "Size: {}", self.bytes.len())?;
98 writeln!(f, "Dependencies: {:?}", self.dependencies)?;
99 Ok(())
100 }
101}
102
103macro_rules! define_system_package_metadata {
104 ([$(($id:expr, $name: expr, $path:expr, $deps:expr)),* $(,)?]) => {{
105 static PACKAGES: LazyLock<Vec<SystemPackageMetadata>> = LazyLock::new(|| {
106 vec![
107 $(SystemPackageMetadata::new(
108 $name,
109 concat!("crates/iota-framework/packages/", $path),
110 $id,
111 include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/packages_compiled", "/", $path)),
112 &$deps,
113 )),*
114 ]
115 });
116 &PACKAGES
117 }}
118}
119
120pub struct BuiltInFramework;
121impl BuiltInFramework {
122 pub fn iter_system_package_metadata() -> impl Iterator<Item = &'static SystemPackageMetadata> {
123 define_system_package_metadata!([
128 (MOVE_STDLIB_PACKAGE_ID, "MoveStdlib", "move-stdlib", []),
129 (
130 IOTA_FRAMEWORK_PACKAGE_ID,
131 "Iota",
132 "iota-framework",
133 [MOVE_STDLIB_PACKAGE_ID]
134 ),
135 (
136 IOTA_SYSTEM_PACKAGE_ID,
137 "IotaSystem",
138 "iota-system",
139 [MOVE_STDLIB_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID]
140 ),
141 (
142 BRIDGE_PACKAGE_ID,
143 "Bridge",
144 "bridge",
145 [
146 MOVE_STDLIB_PACKAGE_ID,
147 IOTA_FRAMEWORK_PACKAGE_ID,
148 IOTA_SYSTEM_PACKAGE_ID
149 ]
150 ),
151 (
152 STARDUST_PACKAGE_ID,
153 "Stardust",
154 "stardust",
155 [MOVE_STDLIB_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID]
156 ),
157 ])
158 .iter()
159 }
160
161 pub fn all_package_ids() -> Vec<ObjectID> {
162 Self::iter_system_packages().map(|p| p.id).collect()
163 }
164
165 pub fn get_package_by_id(id: &ObjectID) -> &'static SystemPackage {
166 Self::iter_system_packages().find(|s| &s.id == id).unwrap()
167 }
168
169 pub fn iter_system_packages() -> impl Iterator<Item = &'static SystemPackage> {
170 BuiltInFramework::iter_system_package_metadata().map(|m| &m.compiled)
171 }
172
173 pub fn genesis_move_packages() -> impl Iterator<Item = MovePackage> {
174 Self::iter_system_packages().map(|package| package.genesis_move_package())
175 }
176
177 pub fn genesis_objects() -> impl Iterator<Item = Object> {
178 Self::iter_system_packages().map(|package| package.genesis_object())
179 }
180}
181
182pub const DEFAULT_FRAMEWORK_PATH: &str = env!("CARGO_MANIFEST_DIR");
183
184pub fn legacy_test_cost() -> InternalGas {
185 InternalGas::new(0)
186}
187
188pub async fn compare_system_package<S: ObjectStore>(
201 object_store: &S,
202 id: &ObjectID,
203 modules: &[CompiledModule],
204 dependencies: Vec<ObjectID>,
205 binary_config: &BinaryConfig,
206) -> Option<ObjectRef> {
207 let cur_object = match object_store.get_object(id) {
208 Ok(Some(cur_object)) => cur_object,
209
210 Ok(None) => {
211 return Some(
213 Object::new_system_package(
214 modules,
215 OBJECT_START_VERSION,
219 dependencies,
220 TransactionDigest::genesis_marker(),
224 )
225 .compute_object_reference(),
226 );
227 }
228
229 Err(e) => {
230 error!("Error loading framework object at {id}: {e:?}");
231 return None;
232 }
233 };
234
235 let cur_ref = cur_object.compute_object_reference();
236 let cur_pkg = cur_object
237 .data
238 .try_as_package()
239 .expect("Framework not package");
240
241 let mut new_object = Object::new_system_package(
242 modules,
243 cur_object.version(),
246 dependencies,
247 cur_object.previous_transaction,
248 );
249
250 if cur_ref == new_object.compute_object_reference() {
251 return Some(cur_ref);
252 }
253
254 let compatibility = Compatibility::framework_upgrade_check();
255
256 let new_pkg = new_object
257 .data
258 .try_as_package_mut()
259 .expect("Created as package");
260
261 let cur_normalized = match cur_pkg.normalize(binary_config) {
262 Ok(v) => v,
263 Err(e) => {
264 error!("Could not normalize existing package: {e:?}");
265 return None;
266 }
267 };
268 let mut new_normalized = new_pkg.normalize(binary_config).ok()?;
269
270 for (name, cur_module) in cur_normalized {
271 let new_module = new_normalized.remove(&name)?;
272
273 if let Err(e) = compatibility.check(&cur_module, &new_module) {
274 error!("Compatibility check failed, for new version of {id}::{name}: {e:?}");
275 return None;
276 }
277 }
278
279 new_pkg.increment_version();
280 Some(new_object.compute_object_reference())
281}