sui_framework_snapshot/
lib.rsuse serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
use std::{fs, io::Read, path::PathBuf};
use sui_framework::{SystemPackage, SystemPackageMetadata};
use sui_protocol_config::ProtocolVersion;
use sui_types::base_types::ObjectID;
use sui_types::{
BRIDGE_PACKAGE_ID, DEEPBOOK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID,
SUI_SYSTEM_PACKAGE_ID,
};
pub type SnapshotManifest = BTreeMap<u64, Snapshot>;
#[derive(Serialize, Deserialize)]
pub struct Snapshot {
pub git_revision: String,
pub packages: Vec<SnapshotPackage>,
}
#[derive(Serialize, Deserialize)]
pub struct SnapshotPackage {
pub name: String,
pub path: String,
pub id: ObjectID,
}
impl Snapshot {
pub fn package_ids(&self) -> impl Iterator<Item = ObjectID> + '_ {
self.packages.iter().map(|p| p.id)
}
}
impl SnapshotPackage {
pub fn from_system_package_metadata(value: &SystemPackageMetadata) -> Self {
Self {
name: value.name.clone(),
path: value.path.clone(),
id: value.compiled.id,
}
}
}
const SYSTEM_PACKAGE_PUBLISH_ORDER: &[ObjectID] = &[
MOVE_STDLIB_PACKAGE_ID,
SUI_FRAMEWORK_PACKAGE_ID,
SUI_SYSTEM_PACKAGE_ID,
DEEPBOOK_PACKAGE_ID,
BRIDGE_PACKAGE_ID,
];
pub fn load_bytecode_snapshot_manifest() -> SnapshotManifest {
let Ok(bytes) = fs::read(manifest_path()) else {
return SnapshotManifest::default();
};
serde_json::from_slice::<SnapshotManifest>(&bytes)
.expect("Could not deserialize SnapshotManifest")
}
pub fn update_bytecode_snapshot_manifest(
git_revision: &str,
version: u64,
files: Vec<SnapshotPackage>,
) {
let mut snapshot = load_bytecode_snapshot_manifest();
snapshot.insert(
version,
Snapshot {
git_revision: git_revision.to_string(),
packages: files,
},
);
let json =
serde_json::to_string_pretty(&snapshot).expect("Could not serialize SnapshotManifest");
fs::write(manifest_path(), json).expect("Could not update manifest file");
}
pub fn load_bytecode_snapshot(protocol_version: u64) -> anyhow::Result<Vec<SystemPackage>> {
let snapshot_path = snapshot_path_for_version(protocol_version)?;
let mut snapshots: BTreeMap<ObjectID, SystemPackage> = fs::read_dir(&snapshot_path)?
.flatten()
.map(|entry| {
let file_name = entry.file_name().to_str().unwrap().to_string();
let mut file = fs::File::open(snapshot_path.clone().join(file_name))?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer)?;
let package: SystemPackage = bcs::from_bytes(&buffer)?;
Ok((package.id, package))
})
.collect::<anyhow::Result<_>>()?;
assert!(snapshots.len() <= SYSTEM_PACKAGE_PUBLISH_ORDER.len());
let mut snapshot_objects = Vec::new();
for package_id in SYSTEM_PACKAGE_PUBLISH_ORDER {
if let Some(object) = snapshots.remove(package_id) {
snapshot_objects.push(object);
}
}
Ok(snapshot_objects)
}
pub fn manifest_path() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("manifest.json")
}
fn snapshot_path_for_version(version: u64) -> anyhow::Result<PathBuf> {
let snapshot_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("bytecode_snapshot");
let mut snapshots = BTreeSet::new();
for entry in fs::read_dir(&snapshot_dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
if let Some(snapshot_number) = path
.file_name()
.and_then(|n| n.to_str())
.and_then(|n| n.parse::<u64>().ok())
{
snapshots.insert(snapshot_number);
}
}
}
if version == ProtocolVersion::MAX.as_u64() && !snapshots.contains(&version) {
anyhow::bail!("No snapshot found for version {}", version)
}
snapshots
.range(..=version)
.next_back()
.map(|v| snapshot_dir.join(v.to_string()))
.ok_or_else(|| anyhow::anyhow!("No snapshot found for version {}", version))
}