/ parameters / src / macros.rs
macros.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  #[macro_export]
 20  macro_rules! checksum {
 21      ($bytes: expr) => {{
 22          use sha2::Digest;
 23          hex::encode(&sha2::Sha256::digest($bytes))
 24      }};
 25  }
 26  
 27  #[macro_export]
 28  macro_rules! checksum_error {
 29      ($expected: expr, $candidate: expr) => {
 30          Err($crate::errors::ParameterError::ChecksumMismatch($expected, $candidate))
 31      };
 32  }
 33  
 34  #[macro_export]
 35  macro_rules! remove_file {
 36      ($filepath:expr) => {
 37          // Safely remove the corrupt file, if it exists.
 38          #[cfg(not(feature = "wasm"))]
 39          if std::path::PathBuf::from(&$filepath).exists() {
 40              match std::fs::remove_file(&$filepath) {
 41                  Ok(()) => println!("Removed {:?}. Please retry the command.", $filepath),
 42                  Err(err) => eprintln!("Failed to remove {:?}: {err}", $filepath),
 43              }
 44          }
 45      };
 46  }
 47  
 48  macro_rules! impl_store_and_remote_fetch {
 49      () => {
 50          #[cfg(not(feature = "wasm"))]
 51          fn store_bytes(buffer: &[u8], file_path: &std::path::Path) -> Result<(), $crate::errors::ParameterError> {
 52              use alphavm_utilities::Write;
 53  
 54              #[cfg(not(feature = "no_std_out"))]
 55              {
 56                  use colored::*;
 57                  let output = format!("{:>15} - Storing file in {:?}", "Installation", file_path);
 58                  println!("{}", output.dimmed());
 59              }
 60  
 61              // Ensure the folders up to the file path all exist.
 62              let mut directory_path = file_path.to_path_buf();
 63              directory_path.pop();
 64              let _ = std::fs::create_dir_all(directory_path)?;
 65  
 66              // Attempt to write the parameter buffer to a file.
 67              match std::fs::File::create(file_path) {
 68                  Ok(mut file) => file.write_all(&buffer)?,
 69                  Err(error) => eprintln!("{}", error),
 70              }
 71              Ok(())
 72          }
 73  
 74          #[cfg(all(not(feature = "wasm"), not(target_env = "sgx")))]
 75          fn remote_fetch(buffer: &mut Vec<u8>, url: &str) -> Result<(), $crate::errors::ParameterError> {
 76              let mut easy = curl::easy::Easy::new();
 77              easy.follow_location(true)?;
 78              easy.url(url)?;
 79  
 80              #[cfg(not(feature = "no_std_out"))]
 81              {
 82                  use colored::*;
 83  
 84                  let output = format!("{:>15} - Downloading \"{}\"", "Installation", url);
 85                  println!("{}", output.dimmed());
 86  
 87                  easy.progress(true)?;
 88                  easy.progress_function(|total_download, current_download, _, _| {
 89                      let percent = (current_download / total_download) * 100.0;
 90                      let size_in_megabytes = total_download as u64 / 1_048_576;
 91                      let output =
 92                          format!("\r{:>15} - {:.2}% complete ({:#} MB total)", "Installation", percent, size_in_megabytes);
 93                      print!("{}", output.dimmed());
 94                      true
 95                  })?;
 96              }
 97  
 98              let mut transfer = easy.transfer();
 99              transfer.write_function(|data| {
100                  buffer.extend_from_slice(data);
101                  Ok(data.len())
102              })?;
103              Ok(transfer.perform()?)
104          }
105  
106          #[cfg(feature = "wasm")]
107          fn remote_fetch(url: &str) -> Result<Vec<u8>, $crate::errors::ParameterError> {
108              // Use the browser's XmlHttpRequest object to download the parameter file synchronously.
109              //
110              // This method blocks the event loop while the parameters are downloaded, and should be
111              // executed in a web worker to prevent the main browser window from freezing.
112              let xhr = web_sys::XmlHttpRequest::new().map_err(|_| {
113                  $crate::errors::ParameterError::Wasm("Download failed - XMLHttpRequest object not found".to_string())
114              })?;
115  
116              // XmlHttpRequest if specified as synchronous cannot use the responseType property. It
117              // cannot thus download bytes directly and enforces a text encoding. To get back the
118              // original binary, a charset that does not corrupt the original bytes must be used.
119              xhr.override_mime_type("octet/binary; charset=ISO-8859-5").unwrap();
120  
121              // Initialize and send the request.
122              xhr.open_with_async("GET", url, false).map_err(|_| {
123                  $crate::errors::ParameterError::Wasm(
124                      "Download failed - This browser does not support synchronous requests".to_string(),
125                  )
126              })?;
127              xhr.send()
128                  .map_err(|_| $crate::errors::ParameterError::Wasm("Download failed - XMLHttpRequest failed".to_string()))?;
129  
130              // Wait for the response in a blocking fashion.
131              if xhr.response().is_ok() && xhr.status().unwrap() == 200 {
132                  // Get the text from the response.
133                  let rust_text = xhr
134                      .response_text()
135                      .map_err(|_| $crate::errors::ParameterError::Wasm("XMLHttpRequest failed".to_string()))?
136                      .ok_or($crate::errors::ParameterError::Wasm(
137                          "The request was successful but no parameters were received".to_string(),
138                      ))?;
139  
140                  // Re-encode the text back into bytes using the chosen encoding.
141                  use encoding::Encoding;
142                  encoding::all::ISO_8859_5
143                      .encode(&rust_text, encoding::EncoderTrap::Strict)
144                      .map_err(|_| $crate::errors::ParameterError::Wasm("Parameter decoding failed".to_string()))
145              } else {
146                  Err($crate::errors::ParameterError::Wasm("Download failed - XMLHttpRequest failed".to_string()))
147              }
148          }
149      };
150  }
151  
152  macro_rules! impl_load_bytes_logic_local {
153      ($filepath: expr, $buffer: expr, $expected_size: expr, $expected_checksum: expr) => {
154          // Ensure the size matches.
155          if $expected_size != $buffer.len() {
156              remove_file!($filepath);
157              return Err($crate::errors::ParameterError::SizeMismatch($expected_size, $buffer.len()));
158          }
159  
160          // Ensure the checksum matches.
161          let candidate_checksum = checksum!($buffer);
162          if $expected_checksum != candidate_checksum {
163              return checksum_error!($expected_checksum, candidate_checksum);
164          }
165  
166          return Ok($buffer.to_vec());
167      };
168  }
169  
170  macro_rules! impl_load_bytes_logic_remote {
171      ($remote_url: expr, $local_dir: expr, $filename: expr, $metadata: expr, $expected_checksum: expr, $expected_size: expr) => {
172          cfg_if::cfg_if! {
173              if #[cfg(all(feature = "filesystem", not(feature="wasm")))] {
174                  // Compose the correct file path for the parameter file.
175                  let mut file_path = acdc_std::alpha_dir();
176                  file_path.push($local_dir);
177                  file_path.push($filename);
178  
179                  let buffer = if file_path.exists() {
180                      // Attempts to load the parameter file locally with an absolute path.
181                      std::fs::read(&file_path)?
182                  } else {
183                      // Downloads the missing parameters and stores it in the local directory for use.
184                      #[cfg(not(feature = "no_std_out"))]
185                      {
186                          use colored::*;
187                          let path = format!("(in {:?})", file_path);
188                          eprintln!(
189                              "\n⚠️  \"{}\" does not exist. Downloading and storing it {}.\n",
190                              $filename, path.dimmed()
191                          );
192                      }
193  
194                      // Load remote file
195                      cfg_if::cfg_if!{
196                          if #[cfg(all(not(feature = "wasm"), not(target_env = "sgx")))] {
197                              let url = format!("{}/{}", $remote_url, $filename);
198                              let mut buffer = vec![];
199                              Self::remote_fetch(&mut buffer, &url)?;
200  
201                              // Ensure the checksum matches.
202                              let candidate_checksum = checksum!(&buffer);
203                              if $expected_checksum != candidate_checksum {
204                                  return checksum_error!($expected_checksum, candidate_checksum)
205                              }
206  
207                              match Self::store_bytes(&buffer, &file_path) {
208                                  Ok(()) => buffer,
209                                  Err(_) => {
210                                      eprintln!(
211                                          "\n❗ Error - Failed to store \"{}\" locally. Please download this file manually and ensure it is stored in {:?}.\n",
212                                          $filename, file_path
213                                      );
214                                      buffer
215                                  }
216                              }
217                          } else {
218                              return Err($crate::errors::ParameterError::RemoteFetchDisabled);
219                          }
220                      }
221                  };
222  
223                  // Ensure the size matches.
224                  if $expected_size != buffer.len() {
225                      remove_file!(file_path);
226                      return Err($crate::errors::ParameterError::SizeMismatch($expected_size, buffer.len()));
227                  }
228  
229                  // Ensure the checksum matches.
230                  let candidate_checksum = checksum!(buffer.as_slice());
231                  if $expected_checksum != candidate_checksum {
232                      return checksum_error!($expected_checksum, candidate_checksum)
233                  }
234                  return Ok(buffer);
235              } else {
236                  cfg_if::cfg_if! {
237                      if #[cfg(feature = "wasm")] {
238                          let url = format!("{}/{}", $remote_url, $filename);
239                          let buffer = Self::remote_fetch(&url)?;
240  
241                          // Ensure the size matches.
242                          if $expected_size != buffer.len() {
243                              remove_file!(file_path);
244                              return Err($crate::errors::ParameterError::SizeMismatch($expected_size, buffer.len()));
245                          }
246  
247                          // Ensure the checksum matches.
248                          let candidate_checksum = checksum!(&buffer);
249                          if $expected_checksum != candidate_checksum {
250                              return checksum_error!($expected_checksum, candidate_checksum)
251                          }
252  
253                          return Ok(buffer)
254                      } else {
255                          return Err($crate::errors::ParameterError::FilesystemDisabled);
256                      }
257                  }
258              }
259          }
260      }
261  }
262  
263  #[macro_export]
264  macro_rules! impl_local {
265      ($name: ident, $local_dir: expr, $fname: tt, "usrs") => {
266          #[derive(Clone, Debug, PartialEq, Eq)]
267          pub struct $name;
268  
269          impl $name {
270              pub const METADATA: &'static str = include_str!(concat!($local_dir, $fname, ".metadata"));
271  
272              pub fn load_bytes() -> Result<Vec<u8>, $crate::errors::ParameterError> {
273                  let metadata: serde_json::Value = serde_json::from_str(Self::METADATA).expect("Metadata was not well-formatted");
274                  let expected_checksum: String = metadata["checksum"].as_str().expect("Failed to parse checksum").to_string();
275                  let expected_size: usize = metadata["size"].to_string().parse().expect("Failed to retrieve the file size");
276  
277                  let _filepath = concat!($local_dir, $fname, ".", "usrs");
278                  let buffer = include_bytes!(concat!($local_dir, $fname, ".", "usrs"));
279  
280                  impl_load_bytes_logic_local!(_filepath, buffer, expected_size, expected_checksum);
281              }
282          }
283  
284          paste::item! {
285              #[cfg(test)]
286              #[test]
287              fn [< test_ $fname _usrs >]() {
288                  assert!($name::load_bytes().is_ok());
289              }
290          }
291      };
292      ($name: ident, $local_dir: expr, $fname: tt, $ftype: tt, $credits_version: tt) => {
293          #[derive(Clone, Debug, PartialEq, Eq)]
294          pub struct $name;
295  
296          impl $name {
297              pub const METADATA: &'static str = include_str!(concat!($local_dir, $credits_version, "/", $fname, ".metadata"));
298  
299              pub fn load_bytes() -> Result<Vec<u8>, $crate::errors::ParameterError> {
300                  let metadata: serde_json::Value = serde_json::from_str(Self::METADATA).expect("Metadata was not well-formatted");
301                  let expected_checksum: String =
302                      metadata[concat!($ftype, "_checksum")].as_str().expect("Failed to parse checksum").to_string();
303                  let expected_size: usize =
304                      metadata[concat!($ftype, "_size")].to_string().parse().expect("Failed to retrieve the file size");
305  
306                  let _filepath = concat!($local_dir, $credits_version, "/", $fname, ".", $ftype);
307                  let buffer = include_bytes!(concat!($local_dir, $credits_version, "/", $fname, ".", $ftype));
308  
309                  impl_load_bytes_logic_local!(_filepath, buffer, expected_size, expected_checksum);
310              }
311          }
312  
313          paste::item! {
314              #[cfg(test)]
315              #[test]
316              fn [< test_ $credits_version _ $fname _ $ftype >]() {
317                  assert!($name::load_bytes().is_ok());
318              }
319          }
320      };
321  }
322  
323  #[macro_export]
324  macro_rules! impl_remote {
325      ($name: ident, $remote_url: expr, $local_dir: expr, $fname: tt, "usrs") => {
326          pub struct $name;
327  
328          impl $name {
329              pub const METADATA: &'static str = include_str!(concat!($local_dir, $fname, ".metadata"));
330  
331              impl_store_and_remote_fetch!();
332  
333              pub fn load_bytes() -> Result<Vec<u8>, $crate::errors::ParameterError> {
334                  let metadata: serde_json::Value = serde_json::from_str(Self::METADATA).expect("Metadata was not well-formatted");
335                  let expected_checksum: String = metadata["checksum"].as_str().expect("Failed to parse checksum").to_string();
336                  let expected_size: usize = metadata["size"].to_string().parse().expect("Failed to retrieve the file size");
337  
338                  // Construct the versioned filename.
339                  let filename = match expected_checksum.get(0..7) {
340                      Some(sum) => format!("{}.{}.{}", $fname, "usrs", sum),
341                      _ => format!("{}.{}", $fname, "usrs"),
342                  };
343  
344                  impl_load_bytes_logic_remote!($remote_url, $local_dir, &filename, metadata, expected_checksum, expected_size);
345              }
346          }
347          paste::item! {
348              #[cfg(test)]
349              #[test]
350              fn [< test_ $fname _usrs >]() {
351                  assert!($name::load_bytes().is_ok());
352              }
353          }
354      };
355      ($name: ident, $remote_url: expr, $local_dir: expr, $fname: tt, $ftype: tt, $credits_version: tt) => {
356          pub struct $name;
357  
358          impl $name {
359              pub const METADATA: &'static str = include_str!(concat!($local_dir, $credits_version, "/", $fname, ".metadata"));
360  
361              impl_store_and_remote_fetch!();
362  
363              pub fn load_bytes() -> Result<Vec<u8>, $crate::errors::ParameterError> {
364                  let metadata: serde_json::Value = serde_json::from_str(Self::METADATA).expect("Metadata was not well-formatted");
365                  let expected_checksum: String =
366                      metadata[concat!($ftype, "_checksum")].as_str().expect("Failed to parse checksum").to_string();
367                  let expected_size: usize =
368                      metadata[concat!($ftype, "_size")].to_string().parse().expect("Failed to retrieve the file size");
369  
370                  // Construct the versioned filename.
371                  let filename = match expected_checksum.get(0..7) {
372                      Some(sum) => format!("{}.{}.{}", $fname, $ftype, sum),
373                      _ => format!("{}.{}", $fname, $ftype),
374                  };
375  
376                  impl_load_bytes_logic_remote!($remote_url, $local_dir, &filename, metadata, expected_checksum, expected_size);
377              }
378  
379              #[cfg(feature = "wasm")]
380              /// Verify external bytes.
381              pub fn verify_bytes(buffer: &[u8]) -> Result<(), $crate::errors::ParameterError> {
382                  let metadata: serde_json::Value = serde_json::from_str(Self::METADATA).expect("Metadata was not well-formatted");
383                  let expected_checksum: String =
384                      metadata[concat!($ftype, "_checksum")].as_str().expect("Failed to parse checksum").to_string();
385                  let expected_size: usize =
386                      metadata[concat!($ftype, "_size")].to_string().parse().expect("Failed to retrieve the file size");
387  
388                  // Ensure the size matches.
389                  if buffer.len() != expected_size {
390                      return Err($crate::errors::ParameterError::SizeMismatch(expected_size, buffer.len()));
391                  }
392  
393                  // Ensure the checksum matches.
394                  let candidate_checksum = checksum!(buffer);
395                  if expected_checksum != candidate_checksum {
396                      return checksum_error!(expected_checksum, candidate_checksum);
397                  }
398                  Ok(())
399              }
400          }
401  
402          paste::item! {
403              #[cfg(test)]
404              #[test]
405              fn [< test_ $credits_version _ $fname _ $ftype >]() {
406                  assert!($name::load_bytes().is_ok());
407              }
408          }
409      };
410  }