diff --git a/Cargo.lock b/Cargo.lock index 0adef0a5..c75a4d73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -629,6 +629,7 @@ dependencies = [ "bitvec 1.0.1", "blockifier 0.8.0-rc.2", "cairo-lang-starknet-classes 2.7.0", + "chrono", "ethers", "eyre", "flate2", diff --git a/Cargo.toml b/Cargo.toml index 9197c26f..7ea0e868 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ gloo-timers = { version = "0.3.0", features = ["futures"] } [dev-dependencies] anyhow = "1.0.89" alloy-primitives = { version = "0.8.5", default-features = false } +chrono = "0.4.38" katana-core = { git = "https://github.com/dojoengine/dojo", tag = "v1.0.0-alpha.9" } katana-executor = { git = "https://github.com/dojoengine/dojo", tag = "v1.0.0-alpha.9" } katana-node = { git = "https://github.com/dojoengine/dojo", tag = "v1.0.0-alpha.9" } diff --git a/tests/account_katana.rs b/tests/account_katana.rs index 3b1181e9..5791ac32 100644 --- a/tests/account_katana.rs +++ b/tests/account_katana.rs @@ -13,13 +13,14 @@ use beerus::{ }; use common::err::Error; use starknet::katana::Katana; +use starknet::scarb::Compiler; use starknet::{ constants::{ CLASS_HASH, COMPILED_ACCOUNT_CONTRACT_V2, COMPILED_ACCOUNT_CONTRACT_V3, CONTRACT_ADDRESS, DECLARE_ACCOUNT_V2, DECLARE_ACCOUNT_V3, SENDER_ADDRESS, }, - executor::Executor, + coordinator::{Coordinator, TestMode}, }; mod common; @@ -48,12 +49,20 @@ async fn declare_deploy_account_v2() { } #[tokio::test] -async fn deploy_multiple_accounts_on_katana() -> Result<(), Error> { +async fn deploy_new_account_on_katana() -> Result<(), Error> { let _katana = Katana::init("http://127.0.0.1:0").await?; - let num_of_new_accounts = 3; - let mut executor = Executor::new(num_of_new_accounts)?; - let update_template = false; - executor.deploy_accounts(update_template)?; + let coordinator = Coordinator::new(TestMode::Katana); + coordinator.copy_template_to_target()?; + coordinator.update_account()?; + let compiler = Compiler::new(&coordinator.target_scarb())?; + compiler.compile().await?; + // TODO + // #804 starkli signer keystore new key.json - Storing somewhere or deleting? + // #804 starkli account oz init account.json - Storing somewhere or deleting? + // #804 declare accounts + // #804 #805 fund accounts from pre-funded account + // #804 deploy accounts + // #806 iterate through class hashes and call getClass to see if they are verified Ok(()) } diff --git a/tests/rpc.rs b/tests/rpc.rs index 1803b8ce..f392af2b 100644 --- a/tests/rpc.rs +++ b/tests/rpc.rs @@ -12,7 +12,6 @@ mod common; mod starknet; use common::err::Error; -use starknet::executor::Executor; #[tokio::test] #[allow(non_snake_case)] @@ -518,10 +517,19 @@ async fn deploy_new_account_on_sepolia() -> Result<(), Error> { // schedule test once each month in separate workflow // with each test, template account id is incremented by 1 // commit from workflows to update latest state of id + let _ctx = setup!("sepolia"); - let num_of_new_accounts = 1; - let _executor = Executor::new(num_of_new_accounts)?; - let _update_template = true; - // executor.deploy_accounts(update_template)?; + // let coordinator = Coordinator::new(TestMode::Sepolia); + // coordinator.copy_template_to_target()?; + // coordinator.update_account()?; + // let compiler = Compiler::new(&coordinator.target_scarb())?; + // compiler.compile().await?; + + // TODO + // #804 starkli signer keystore new key.json - Storing somewhere or deleting? + // #804 starkli account oz init account.json - Storing somewhere or deleting? + // #804 declare account + // #804 #805 fund account from pre-funded account + // #804 deploy account Ok(()) } diff --git a/tests/starknet/contract/account/src/lib.cairo b/tests/starknet/contract/account/src/lib.cairo index 07e6f11f..f64cba68 100644 --- a/tests/starknet/contract/account/src/lib.cairo +++ b/tests/starknet/contract/account/src/lib.cairo @@ -35,7 +35,7 @@ mod Account { #[constructor] fn constructor(ref self: ContractState, public_key: felt252) { self.public_key.write(public_key); - self.id.write(0); + self.id.write(); } #[abi(embed_v0)] diff --git a/tests/starknet/coordinator.rs b/tests/starknet/coordinator.rs new file mode 100644 index 00000000..417693fb --- /dev/null +++ b/tests/starknet/coordinator.rs @@ -0,0 +1,82 @@ +use std::fs; + +use anyhow::Error; +use chrono; + +#[allow(dead_code)] +pub enum TestMode { + Katana, + Sepolia, +} + +#[allow(dead_code)] +pub struct Coordinator { + id: String, + mode: TestMode, + source: String, + target: String, +} + +#[allow(dead_code)] +impl Coordinator { + pub fn new(mode: TestMode) -> Self { + let now = chrono::offset::Local::now(); + let id = now.format("%Y%m%y%H%M%S").to_string(); + let target = "./target/account-".to_string() + &id; + Self { + id, + mode, + source: "./tests/starknet/contract/account".to_string(), + target, + } + } + + pub fn copy_template_to_target(&self) -> Result<(), Error> { + fs::create_dir(&self.target)?; + fs::create_dir(self.target_src())?; + fs::copy(self.source_lib(), self.target_lib())?; + fs::copy(self.source_scarb(), self.target_scarb())?; + Ok(()) + } + + pub fn update_account(&self) -> Result<(), Error> { + let account_template = fs::read_to_string(self.target_lib())?; + let account_new = account_template.replace("", &self.id); + fs::write(self.target_lib(), account_new)?; + Ok(()) + } + + pub fn source_lib(&self) -> String { + self.source.clone() + "/src/lib.cairo" + } + + pub fn source_scarb(&self) -> String { + self.source.clone() + "/Scarb.toml" + } + + pub fn target_lib(&self) -> String { + self.target.clone() + "/src/lib.cairo" + } + + pub fn target_scarb(&self) -> String { + self.target.clone() + "/Scarb.toml" + } + + pub fn target_src(&self) -> String { + self.target.clone() + "/src" + } +} + +impl Drop for Coordinator { + fn drop(&mut self) { + match self.mode { + TestMode::Katana => { + let target = self.target.clone(); + if fs::exists(&target).unwrap() { + fs::remove_dir_all(target).unwrap() + } + } + TestMode::Sepolia => {} + } + } +} diff --git a/tests/starknet/executor.rs b/tests/starknet/executor.rs deleted file mode 100644 index 8da68e84..00000000 --- a/tests/starknet/executor.rs +++ /dev/null @@ -1,128 +0,0 @@ -use std::{fs, thread}; - -use anyhow::{anyhow, Error}; -use regex::Regex; - -use super::scarb::Compiler; - -#[allow(dead_code)] -pub struct Executor { - accounts: Vec, -} - -#[allow(dead_code)] -impl Executor { - pub fn new(num: usize) -> Result { - let template = "./tests/starknet/contract/account".to_string(); - let mut accounts = Vec::with_capacity(num); - accounts.push(template); - Ok(Self { accounts }) - } - - pub fn deploy_accounts( - &mut self, - update_template: bool, - ) -> Result<(), Error> { - if update_template { - self.update_account(&self.accounts[0])?; - } - self.prepare_contracts_environment()?; - self.compile()?; - // TODO - // #804 starkli signer keystore new key.json - Storing somewhere or deleting? - // #804 starkli account oz init account.json - Storing somewhere or deleting? - // #804 declare accounts - // #804 #805 fund accounts from pre-funded account - // #804 deploy accounts - // #806 iterate through class hashes and call getClass to see if they are verified - Ok(()) - } - - fn update_account(&self, path: &str) -> Result<(), Error> { - let lib_path = path.to_owned() + "/src/lib.cairo"; - let account_old = fs::read_to_string(lib_path.clone())?; - let re = Regex::new(r"self.id.write\((?\d+)\);")?; - - let Some(val) = re.captures(&account_old) else { - return Err(anyhow!("Could not find pattern in lib.cairo.")); - }; - let num_old = - &val["number"].parse::().expect("Failed to read number"); - let num_new = num_old + 1; - let account_new = account_old.replace( - &format!("self.id.write({num_old})"), - &format!("self.id.write({num_new})"), - ); - fs::write(lib_path, account_new)?; - - Ok(()) - } - - fn prepare_contracts_environment(&mut self) -> Result<(), Error> { - let capacity = self.accounts.capacity(); - let template = self.accounts[0].clone(); - let lib_path = "/src/lib.cairo"; - let toml_path = "/Scarb.toml"; - - for i in 1..capacity { - let account = template.clone() + &i.to_string(); - fs::create_dir(account.clone())?; - fs::create_dir(account.clone() + "/src")?; - fs::copy( - self.accounts[i - 1].clone() + lib_path, - account.clone() + lib_path, - )?; - fs::copy( - template.clone() + toml_path, - account.clone() + toml_path, - )?; - self.update_account(&account)?; - self.accounts.push(account); - } - - Ok(()) - } - - fn compile(&self) -> Result<(), Error> { - let mut vec_of_threads = Vec::with_capacity(self.accounts.len()); - - for account in self.accounts.iter() { - let path = account.clone() + "/Scarb.toml"; - let compilation = thread::spawn(move || -> Result<(), Error> { - let compiler = Compiler::new(&path)?; - compiler.compile() - }); - vec_of_threads.push(compilation); - } - for (i, thread) in vec_of_threads.into_iter().enumerate() { - let compilation = thread.join(); - match compilation { - Ok(val) => val?, - Err(e) => { - return Err(anyhow!("Error during thread {i} execution. Original error message: {:#?}", e)); - } - } - } - - Ok(()) - } -} - -impl Drop for Executor { - fn drop(&mut self) { - let dir = self.accounts[0].clone() + "/target"; - let scarb = self.accounts[0].clone() + "/Scarb.lock"; - if fs::exists(dir.clone()).expect("Failed to check template target") { - fs::remove_dir_all(dir).expect("Failed to remove template target"); - }; - if fs::exists(scarb.clone()).expect("Failed to check template Scarb") { - fs::remove_file(scarb).expect("Failed to remove template Scarb"); - } - for i in 1..self.accounts.len() { - let dir = self.accounts[i].clone(); - if fs::exists(dir.clone()).expect("Failed to check account dir") { - fs::remove_dir_all(dir).expect("Failed to remove account dir"); - } - } - } -} diff --git a/tests/starknet/mod.rs b/tests/starknet/mod.rs index 26d7e2bf..280a6a6d 100644 --- a/tests/starknet/mod.rs +++ b/tests/starknet/mod.rs @@ -1,4 +1,4 @@ pub mod constants; -pub mod executor; +pub mod coordinator; pub mod katana; pub mod scarb; diff --git a/tests/starknet/scarb.rs b/tests/starknet/scarb.rs index cb75e22a..37449ce5 100644 --- a/tests/starknet/scarb.rs +++ b/tests/starknet/scarb.rs @@ -1,4 +1,4 @@ -use anyhow::Error; +use anyhow::{anyhow, Error}; use scarb::{ core::{Config, PackageId, PackageName, SourceId, TargetKind}, ops::{self, CompileOpts, FeaturesOpts, FeaturesSelector}, @@ -35,7 +35,21 @@ impl Compiler { Ok(Compiler { toml: toml_absolute, opts, packages }) } - pub fn compile(self) -> Result<(), Error> { + pub async fn compile(self) -> Result<(), Error> { + let compilation = + tokio::task::spawn_blocking(move || -> Result<(), Error> { + self.run_compilation() + }); + match compilation.await { + Ok(val) => Ok(val?), + Err(e) => Err(anyhow!( + "Error during thread execution. Original error message: {:#?}", + e, + )), + } + } + + fn run_compilation(self) -> Result<(), Error> { let config = Config::builder(self.toml.to_str().unwrap()).build()?; let ws = ops::read_workspace(config.manifest_path(), &config)?; scarb::ops::compile(self.packages, self.opts, &ws)