iota_framework_snapshot/
lib.rs1use std::{
6 collections::{BTreeMap, BTreeSet},
7 fs,
8 io::Read,
9 path::PathBuf,
10};
11
12use iota_framework::{SystemPackage, SystemPackageMetadata};
13use iota_types::{
14 BRIDGE_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID, IOTA_SYSTEM_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID,
15 STARDUST_PACKAGE_ID, base_types::ObjectID,
16};
17use serde::{Deserialize, Serialize};
18
19pub type SnapshotManifest = BTreeMap<u64, Snapshot>;
20
21#[derive(Serialize, Deserialize)]
35pub struct Snapshot {
36 pub git_revision: String,
38
39 pub packages: Vec<SnapshotPackage>,
41}
42
43#[derive(Serialize, Deserialize)]
46pub struct SnapshotPackage {
47 pub name: String,
49 pub path: String,
52 pub id: ObjectID,
54}
55
56impl Snapshot {
57 pub fn package_ids(&self) -> impl Iterator<Item = ObjectID> + '_ {
58 self.packages.iter().map(|p| p.id)
59 }
60}
61
62impl SnapshotPackage {
63 pub fn from_system_package_metadata(value: &SystemPackageMetadata) -> Self {
64 Self {
65 name: value.name.clone(),
66 path: value.path.clone(),
67 id: value.compiled.id,
68 }
69 }
70}
71
72const SYSTEM_PACKAGE_PUBLISH_ORDER: &[ObjectID] = &[
73 MOVE_STDLIB_PACKAGE_ID,
74 IOTA_FRAMEWORK_PACKAGE_ID,
75 IOTA_SYSTEM_PACKAGE_ID,
76 BRIDGE_PACKAGE_ID,
77 STARDUST_PACKAGE_ID,
78];
79
80pub fn load_bytecode_snapshot_manifest() -> SnapshotManifest {
81 let Ok(bytes) = fs::read(manifest_path()) else {
82 return SnapshotManifest::default();
83 };
84 serde_json::from_slice::<SnapshotManifest>(&bytes)
85 .expect("Could not deserialize SnapshotManifest")
86}
87
88pub fn update_bytecode_snapshot_manifest(
89 git_revision: &str,
90 version: u64,
91 files: Vec<SnapshotPackage>,
92) {
93 let mut snapshot = load_bytecode_snapshot_manifest();
94
95 snapshot.insert(
96 version,
97 Snapshot {
98 git_revision: git_revision.to_string(),
99 packages: files,
100 },
101 );
102
103 let json =
104 serde_json::to_string_pretty(&snapshot).expect("Could not serialize SnapshotManifest");
105 fs::write(manifest_path(), json).expect("Could not update manifest file");
106}
107
108pub fn load_bytecode_snapshot(protocol_version: u64) -> anyhow::Result<Vec<SystemPackage>> {
109 let snapshot_path = snapshot_path_for_version(protocol_version)?;
110 let mut snapshots: BTreeMap<ObjectID, SystemPackage> = fs::read_dir(&snapshot_path)?
111 .flatten()
112 .map(|entry| {
113 let file_name = entry.file_name().to_str().unwrap().to_string();
114 let mut file = fs::File::open(snapshot_path.clone().join(file_name))?;
115 let mut buffer = Vec::new();
116 file.read_to_end(&mut buffer)?;
117 let package: SystemPackage = bcs::from_bytes(&buffer)?;
118 Ok((package.id, package))
119 })
120 .collect::<anyhow::Result<_>>()?;
121
122 assert!(snapshots.len() <= SYSTEM_PACKAGE_PUBLISH_ORDER.len());
124 let mut snapshot_objects = Vec::new();
125 for package_id in SYSTEM_PACKAGE_PUBLISH_ORDER {
126 if let Some(object) = snapshots.remove(package_id) {
127 snapshot_objects.push(object);
128 }
129 }
130 Ok(snapshot_objects)
131}
132
133pub fn manifest_path() -> PathBuf {
134 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("manifest.json")
135}
136
137fn snapshot_path_for_version(version: u64) -> anyhow::Result<PathBuf> {
146 let snapshot_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("bytecode_snapshot");
147 let mut snapshots = BTreeSet::new();
148
149 for entry in fs::read_dir(&snapshot_dir)? {
150 let entry = entry?;
151 let path = entry.path();
152 if path.is_dir() {
153 if let Some(snapshot_number) = path
154 .file_name()
155 .and_then(|n| n.to_str())
156 .and_then(|n| n.parse::<u64>().ok())
157 {
158 snapshots.insert(snapshot_number);
159 }
160 }
161 }
162
163 snapshots
164 .range(version..)
165 .next()
166 .map(|v| snapshot_dir.join(v.to_string()))
167 .ok_or_else(|| anyhow::anyhow!("No snapshot found for version {}", version))
168}