|
| 1 | +use std::collections::BTreeMap; |
| 2 | +use std::collections::BTreeSet; |
| 3 | +use std::fmt::Write as _; |
| 4 | +use std::fs; |
| 5 | +use std::path::Path; |
| 6 | + |
| 7 | +pub type ArtifactId = String; |
| 8 | +pub type FileContent = String; |
| 9 | + |
| 10 | +/// In memory representation of a folder containing data imported using the `scripts/import.sh` script |
| 11 | +/// of the fake aggregator. |
| 12 | +/// |
| 13 | +/// List items are just their corresponding file content loaded in memory. |
| 14 | +/// Individual items are btreemap with the source filename as key and the file content as value. |
| 15 | +#[derive(Debug, Default)] |
| 16 | +pub struct DataFolder { |
| 17 | + epoch_settings: FileContent, |
| 18 | + |
| 19 | + certificates_list: FileContent, |
| 20 | + individual_certificates: BTreeMap<ArtifactId, FileContent>, |
| 21 | + |
| 22 | + snapshots_list: FileContent, |
| 23 | + individual_snapshots: BTreeMap<ArtifactId, FileContent>, |
| 24 | + |
| 25 | + msds_list: FileContent, |
| 26 | + individual_msds: BTreeMap<ArtifactId, FileContent>, |
| 27 | + |
| 28 | + ctx_commitments_list: FileContent, |
| 29 | + individual_ctx_commitments: BTreeMap<ArtifactId, FileContent>, |
| 30 | + ctx_proofs: BTreeMap<ArtifactId, FileContent>, |
| 31 | +} |
| 32 | + |
| 33 | +impl DataFolder { |
| 34 | + pub fn load_from_folder(folder: &Path) -> Self { |
| 35 | + fn extract_artifact_id(filename: &str, prefix: &str) -> String { |
| 36 | + let id_with_extension = filename.strip_prefix(prefix).unwrap(); |
| 37 | + id_with_extension.strip_suffix(".json").unwrap().to_string() |
| 38 | + } |
| 39 | + |
| 40 | + let mut data_folder = DataFolder::default(); |
| 41 | + |
| 42 | + for entry in list_json_files_in_folder(folder) { |
| 43 | + let filename = entry.file_name().to_string_lossy().to_string(); |
| 44 | + let file_content = fs::read_to_string(&entry.path()).unwrap_or_else(|_| { |
| 45 | + panic!( |
| 46 | + "Could not read file content, file_path: {}", |
| 47 | + entry.path().display() |
| 48 | + ) |
| 49 | + }); |
| 50 | + |
| 51 | + match filename.as_str() { |
| 52 | + "epoch-settings.json" => { |
| 53 | + data_folder.epoch_settings = file_content; |
| 54 | + } |
| 55 | + "mithril-stake-distributions.json" => { |
| 56 | + data_folder.msds_list = file_content; |
| 57 | + } |
| 58 | + "snapshots.json" => { |
| 59 | + data_folder.snapshots_list = file_content; |
| 60 | + } |
| 61 | + "certificates.json" => { |
| 62 | + data_folder.certificates_list = file_content; |
| 63 | + } |
| 64 | + "ctx-commitments.json" => { |
| 65 | + data_folder.ctx_commitments_list = file_content; |
| 66 | + } |
| 67 | + _ if filename.starts_with("mithril-stake-distribution-") => { |
| 68 | + data_folder.individual_msds.insert( |
| 69 | + extract_artifact_id(&filename, "mithril-stake-distribution-"), |
| 70 | + file_content, |
| 71 | + ); |
| 72 | + } |
| 73 | + _ if filename.starts_with("snapshot-") => { |
| 74 | + data_folder |
| 75 | + .individual_snapshots |
| 76 | + .insert(extract_artifact_id(&filename, "snapshot-"), file_content); |
| 77 | + } |
| 78 | + _ if filename.starts_with("certificate-") => { |
| 79 | + data_folder |
| 80 | + .individual_certificates |
| 81 | + .insert(extract_artifact_id(&filename, "certificate-"), file_content); |
| 82 | + } |
| 83 | + _ if filename.starts_with("ctx-commitment-") => { |
| 84 | + data_folder.individual_ctx_commitments.insert( |
| 85 | + extract_artifact_id(&filename, "ctx-commitment-"), |
| 86 | + file_content, |
| 87 | + ); |
| 88 | + } |
| 89 | + _ if filename.starts_with("ctx-proof-") => { |
| 90 | + data_folder |
| 91 | + .ctx_proofs |
| 92 | + .insert(extract_artifact_id(&filename, "ctx-proof-"), file_content); |
| 93 | + } |
| 94 | + // unknown file |
| 95 | + _ => {} |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + data_folder |
| 100 | + } |
| 101 | + |
| 102 | + pub fn generate_code_for_all_data(self) -> String { |
| 103 | + format!( |
| 104 | + "use std::collections::BTreeMap; |
| 105 | +
|
| 106 | +{} |
| 107 | +", |
| 108 | + [ |
| 109 | + generate_list_getter("epoch_settings", self.epoch_settings), |
| 110 | + generate_ids_array( |
| 111 | + "snapshot_digests", |
| 112 | + BTreeSet::from_iter(self.individual_snapshots.keys().cloned()) |
| 113 | + ), |
| 114 | + generate_artifact_getter("snapshots", self.individual_snapshots), |
| 115 | + generate_list_getter("snapshot_list", self.snapshots_list), |
| 116 | + generate_ids_array( |
| 117 | + "msd_hashes", |
| 118 | + BTreeSet::from_iter(self.individual_msds.keys().cloned()) |
| 119 | + ), |
| 120 | + generate_artifact_getter("msds", self.individual_msds), |
| 121 | + generate_list_getter("msd_list", self.msds_list), |
| 122 | + generate_ids_array( |
| 123 | + "certificate_hashes", |
| 124 | + BTreeSet::from_iter(self.individual_certificates.keys().cloned()) |
| 125 | + ), |
| 126 | + generate_artifact_getter("certificates", self.individual_certificates), |
| 127 | + generate_list_getter("certificate_list", self.certificates_list), |
| 128 | + generate_ids_array( |
| 129 | + "ctx_commitment_hashes", |
| 130 | + BTreeSet::from_iter(self.individual_ctx_commitments.keys().cloned()) |
| 131 | + ), |
| 132 | + generate_artifact_getter("ctx_commitments", self.individual_ctx_commitments), |
| 133 | + generate_list_getter("ctx_commitments_list", self.ctx_commitments_list), |
| 134 | + generate_ids_array( |
| 135 | + "proof_transaction_hashes", |
| 136 | + BTreeSet::from_iter(self.ctx_proofs.keys().cloned()) |
| 137 | + ), |
| 138 | + generate_artifact_getter("ctx_proofs", self.ctx_proofs), |
| 139 | + ] |
| 140 | + .join( |
| 141 | + " |
| 142 | +
|
| 143 | +" |
| 144 | + ) |
| 145 | + ) |
| 146 | + } |
| 147 | +} |
| 148 | + |
| 149 | +pub fn list_json_files_in_folder(folder: &Path) -> impl Iterator<Item = std::fs::DirEntry> + '_ { |
| 150 | + fs::read_dir(folder) |
| 151 | + .unwrap_or_else(|_| panic!("Could not read `{}` dir", folder.display())) |
| 152 | + .filter_map(move |e| { |
| 153 | + let entry = e.unwrap_or_else(|_| { |
| 154 | + panic!("Failed to read a file in the `{}` dir", folder.display()) |
| 155 | + }); |
| 156 | + match entry.file_type() { |
| 157 | + Ok(file_type) if file_type.is_file() => Some(entry), |
| 158 | + _ => None, |
| 159 | + } |
| 160 | + }) |
| 161 | + .filter(|e| e.file_name().to_string_lossy().ends_with(".json")) |
| 162 | +} |
| 163 | + |
| 164 | +// pub(crate) fn $fun_name()() -> BTreeMap<String, String> |
| 165 | +pub fn generate_artifact_getter( |
| 166 | + fun_name: &str, |
| 167 | + source_jsons: BTreeMap<ArtifactId, FileContent>, |
| 168 | +) -> String { |
| 169 | + let mut artifacts_list = String::new(); |
| 170 | + |
| 171 | + for (artifact_id, file_content) in source_jsons { |
| 172 | + write!( |
| 173 | + artifacts_list, |
| 174 | + r###" |
| 175 | + ( |
| 176 | + "{}", |
| 177 | + r#"{}"# |
| 178 | + ),"###, |
| 179 | + artifact_id, file_content |
| 180 | + ) |
| 181 | + .unwrap(); |
| 182 | + } |
| 183 | + |
| 184 | + format!( |
| 185 | + r###"pub(crate) fn {}() -> BTreeMap<String, String> {{ |
| 186 | + [{} |
| 187 | + ] |
| 188 | + .into_iter() |
| 189 | + .map(|(k, v)| (k.to_owned(), v.to_owned())) |
| 190 | + .collect() |
| 191 | +}}"###, |
| 192 | + fun_name, artifacts_list |
| 193 | + ) |
| 194 | +} |
| 195 | + |
| 196 | +/// pub(crate) fn $fun_name() -> &'static str |
| 197 | +pub fn generate_list_getter(fun_name: &str, source_json: FileContent) -> String { |
| 198 | + format!( |
| 199 | + r###"pub(crate) fn {}() -> &'static str {{ |
| 200 | + r#"{}"# |
| 201 | +}}"###, |
| 202 | + fun_name, source_json |
| 203 | + ) |
| 204 | +} |
| 205 | + |
| 206 | +/// pub(crate) fn $fun_name() -> &'static str |
| 207 | +pub fn generate_ids_array(array_name: &str, ids: BTreeSet<ArtifactId>) -> String { |
| 208 | + let mut ids_list = String::new(); |
| 209 | + |
| 210 | + for id in &ids { |
| 211 | + write!( |
| 212 | + ids_list, |
| 213 | + r#" |
| 214 | + "{}","#, |
| 215 | + id |
| 216 | + ) |
| 217 | + .unwrap(); |
| 218 | + } |
| 219 | + |
| 220 | + format!( |
| 221 | + r###"pub(crate) const fn {}<'a>() -> [&'a str; {}] {{ |
| 222 | + [{} |
| 223 | + ] |
| 224 | +}}"###, |
| 225 | + array_name, |
| 226 | + ids.len(), |
| 227 | + ids_list, |
| 228 | + ) |
| 229 | +} |
| 230 | + |
| 231 | +#[cfg(test)] |
| 232 | +mod tests { |
| 233 | + use super::*; |
| 234 | +} |
0 commit comments