#![allow(dead_code)]
use std::collections::HashSet;
use std::path::PathBuf;
use std::sync::Arc;
use crate::cairo_runner::pre_run::PreRunner;
use crate::pre_processor::ExtendedModule;
use crate::{cairo_runner::input::pre_run::PreRunnerInput, module_registry::ModuleRegistry};
use anyhow::{Ok, Result};
use futures::future::join_all;
use hdp_primitives::{module::Module, processed_types::module::ProcessedModule};
use hdp_provider::key::FetchKeyEnvelope;
use starknet::providers::Url;
use tempfile::NamedTempFile;
use tokio::task;
use tracing::info;
pub(crate) struct ModuleCompiler {
pre_runner: PreRunner,
module_registry: Arc<ModuleRegistry>,
}
pub struct ModuleCompilerConfig {
pub module_registry_rpc_url: Url,
pub program_path: PathBuf,
}
pub struct PreProcessResult {
pub fetch_keys: Vec<FetchKeyEnvelope>,
pub modules: Vec<Module>,
}
impl ModuleCompiler {
pub fn new_with_config(config: ModuleCompilerConfig) -> Self {
let rpc_url = config.module_registry_rpc_url;
let program_path = config.program_path;
let module_registry = ModuleRegistry::new(rpc_url);
let pre_runner = PreRunner::new(program_path);
Self {
pre_runner,
module_registry: Arc::new(module_registry),
}
}
pub async fn compile(
&self,
modules: Vec<Module>,
) -> Result<(HashSet<FetchKeyEnvelope>, Vec<ExtendedModule>)> {
info!("Generating input data for preprocessor...");
let extended_modules = self.fetch_modules_class(modules.clone()).await?;
let identified_keys_file = NamedTempFile::new().unwrap().path().to_path_buf();
let input = self
.generate_input(extended_modules.clone(), identified_keys_file)
.await?;
let input_string =
serde_json::to_string_pretty(&input).expect("Failed to serialize module class");
info!("Running preprocessor...");
info!("Preprocessor completed successfully");
let keys: HashSet<FetchKeyEnvelope> =
self.pre_runner.run(input_string)?.into_iter().collect();
Ok((keys, extended_modules))
}
async fn fetch_modules_class(&self, modules: Vec<Module>) -> Result<Vec<ExtendedModule>> {
let registry: Arc<ModuleRegistry> = Arc::clone(&self.module_registry);
let module_futures: Vec<_> = modules
.into_iter()
.map(|module| {
let module_registry = Arc::clone(®istry);
task::spawn(async move {
let module_hash = module.class_hash;
let module_class = module_registry.get_module_class(module_hash).await.unwrap();
Ok(ExtendedModule {
task: module,
module_class,
})
})
})
.collect();
let results: Vec<_> = join_all(module_futures).await;
let mut collected_results = Vec::new();
for result in results {
let module_with_class = result??;
collected_results.push(module_with_class);
}
Ok(collected_results)
}
async fn generate_input(
&self,
extended_modules: Vec<ExtendedModule>,
identified_keys_file: PathBuf,
) -> Result<PreRunnerInput> {
let mut collected_results = Vec::new();
for module in extended_modules {
let input_module = ProcessedModule::new(module.task.inputs, module.module_class);
collected_results.push(input_module);
}
Ok(PreRunnerInput {
identified_keys_file,
modules: collected_results,
})
}
}
#[cfg(test)]
mod tests {
use hdp_primitives::module::ModuleTag;
use starknet::macros::felt;
use super::*;
#[ignore = "ignore for now"]
#[tokio::test]
async fn test_pre_processor() {
let url: &str =
"https://starknet-sepolia.g.alchemy.com/v2/lINonYKIlp4NH9ZI6wvqJ4HeZj7T4Wm6";
let program_path = "../../build/compiled_cairo/hdp.json";
let pre_processor = ModuleCompiler::new_with_config(ModuleCompilerConfig {
module_registry_rpc_url: url.parse().unwrap(),
program_path: PathBuf::from(program_path),
});
let module = Module::from_tag(ModuleTag::TEST, vec![felt!("1"), felt!("2")]);
let module2 = Module::from_tag(ModuleTag::TEST, vec![felt!("1"), felt!("2")]);
let _ = pre_processor
.compile(vec![module.clone(), module2.clone()])
.await
.unwrap();
}
}