From 54c4df6d330b89fd06298020d511f82d75217d76 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 28 Nov 2023 22:43:14 +0400 Subject: [PATCH 1/3] Add test --- crates/forge/tests/cli/multi_script.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/forge/tests/cli/multi_script.rs b/crates/forge/tests/cli/multi_script.rs index fb052b40b8a8..f6f3adb9dadb 100644 --- a/crates/forge/tests/cli/multi_script.rs +++ b/crates/forge/tests/cli/multi_script.rs @@ -61,3 +61,18 @@ forgetest_async!(can_not_change_fork_during_broadcast, |prj, cmd| { .args(&[&handle1.http_endpoint(), &handle2.http_endpoint()]) .broadcast(ScriptOutcome::ErrorSelectForkOnBroadcast); }); + +forgetest_async!(can_resume_multi_chain_script, |prj, cmd| { + let (_, handle1) = spawn(NodeConfig::test()).await; + let (_, handle2) = spawn(NodeConfig::test()).await; + let mut tester = ScriptTester::new_broadcast_without_endpoint(cmd, prj.root()); + + tester + .add_sig("MultiChainBroadcastNoLink", "deploy(string memory,string memory)") + .args(&[&handle1.http_endpoint(), &handle2.http_endpoint()]) + .broadcast(ScriptOutcome::MissingWallet) + .load_private_keys(&[0, 1]) + .await + .arg("--multi") + .resume(ScriptOutcome::OkBroadcast); +}); From 5f1f3488e6909d21d41fce3998a63ff4969f2fbd Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 22 Nov 2023 04:32:28 +0400 Subject: [PATCH 2/3] Multi script caching --- crates/forge/bin/cmd/script/broadcast.rs | 2 +- crates/forge/bin/cmd/script/cmd.rs | 2 +- crates/forge/bin/cmd/script/multi.rs | 114 ++++++++++++++++++----- crates/forge/bin/cmd/script/sequence.rs | 15 +-- 4 files changed, 102 insertions(+), 31 deletions(-) diff --git a/crates/forge/bin/cmd/script/broadcast.rs b/crates/forge/bin/cmd/script/broadcast.rs index 270552ec78d7..a0523ba918ad 100644 --- a/crates/forge/bin/cmd/script/broadcast.rs +++ b/crates/forge/bin/cmd/script/broadcast.rs @@ -296,7 +296,7 @@ impl ScriptArgs { deployments.clone(), &self.sig, script_config.target_contract(), - &script_config.config.broadcast, + &script_config.config, self.broadcast, )?; diff --git a/crates/forge/bin/cmd/script/cmd.rs b/crates/forge/bin/cmd/script/cmd.rs index 3fbdfc514950..5aadaa977104 100644 --- a/crates/forge/bin/cmd/script/cmd.rs +++ b/crates/forge/bin/cmd/script/cmd.rs @@ -192,7 +192,7 @@ impl ScriptArgs { return self .multi_chain_deployment( MultiChainSequence::load( - &script_config.config.broadcast, + &script_config.config, &self.sig, script_config.target_contract(), )?, diff --git a/crates/forge/bin/cmd/script/multi.rs b/crates/forge/bin/cmd/script/multi.rs index 7fa4709a9634..1c53229a24f2 100644 --- a/crates/forge/bin/cmd/script/multi.rs +++ b/crates/forge/bin/cmd/script/multi.rs @@ -1,6 +1,6 @@ use super::{ receipts, - sequence::{ScriptSequence, DRY_RUN_DIR}, + sequence::{sig_to_file_name, ScriptSequence, SensitiveScriptSequence, DRY_RUN_DIR}, verify::VerifyBundle, ScriptArgs, }; @@ -22,10 +22,27 @@ use std::{ #[derive(Deserialize, Serialize, Clone, Default)] pub struct MultiChainSequence { pub deployments: Vec, + #[serde(skip)] pub path: PathBuf, + #[serde(skip)] + pub sensitive_path: PathBuf, pub timestamp: u64, } +/// Sensitive values from script sequences. +#[derive(Deserialize, Serialize, Clone, Default)] +pub struct SensitiveMultiChainSequence { + pub deployments: Vec, +} + +impl From<&mut MultiChainSequence> for SensitiveMultiChainSequence { + fn from(sequence: &mut MultiChainSequence) -> Self { + SensitiveMultiChainSequence { + deployments: sequence.deployments.iter_mut().map(|sequence| sequence.into()).collect(), + } + } +} + impl Drop for MultiChainSequence { fn drop(&mut self) { self.deployments.iter_mut().for_each(|sequence| sequence.sort_receipts()); @@ -38,26 +55,38 @@ impl MultiChainSequence { deployments: Vec, sig: &str, target: &ArtifactId, - log_folder: &Path, + config: &Config, broadcasted: bool, ) -> Result { - let path = - MultiChainSequence::get_path(&log_folder.join("multi"), sig, target, broadcasted)?; - - Ok(MultiChainSequence { deployments, path, timestamp: now().as_secs() }) + let (path, sensitive_path) = MultiChainSequence::get_paths( + &config.broadcast, + &config.cache_path, + sig, + target, + broadcasted, + )?; + + Ok(MultiChainSequence { deployments, path, sensitive_path, timestamp: now().as_secs() }) } - /// Saves to ./broadcast/multi/contract_filename[-timestamp]/sig.json - pub fn get_path( - out: &Path, + /// Gets paths in the formats + /// ./broadcast/multi/contract_filename[-timestamp]/sig.json and + /// ./cache/multi/contract_filename[-timestamp]/sig.json + pub fn get_paths( + broadcast: &Path, + cache: &Path, sig: &str, target: &ArtifactId, broadcasted: bool, - ) -> Result { - let mut out = out.to_path_buf(); + ) -> Result<(PathBuf, PathBuf)> { + let mut broadcast = broadcast.to_path_buf(); + let mut cache = cache.to_path_buf(); + let mut common = PathBuf::new(); + + common.push("multi"); if !broadcasted { - out.push(DRY_RUN_DIR); + common.push(DRY_RUN_DIR); } let target_fname = target @@ -65,29 +94,55 @@ impl MultiChainSequence { .file_name() .wrap_err_with(|| format!("No filename for {:?}", target.source))? .to_string_lossy(); - out.push(format!("{target_fname}-latest")); - fs::create_dir_all(&out)?; + common.push(format!("{target_fname}-latest")); + + broadcast.push(common.clone()); + cache.push(common); - let filename = sig - .split_once('(') - .wrap_err_with(|| format!("Failed to compute file name: Signature {sig} is invalid."))? - .0; - out.push(format!("{filename}.json")); + fs::create_dir_all(&broadcast)?; + fs::create_dir_all(&cache)?; - Ok(out) + let filename = format!("{}.json", sig_to_file_name(sig)); + + broadcast.push(filename.clone()); + cache.push(filename); + + Ok((broadcast, cache)) } /// Loads the sequences for the multi chain deployment. - pub fn load(log_folder: &Path, sig: &str, target: &ArtifactId) -> Result { - let path = MultiChainSequence::get_path(&log_folder.join("multi"), sig, target, true)?; - foundry_compilers::utils::read_json_file(path).wrap_err("Multi-chain deployment not found.") + pub fn load(config: &Config, sig: &str, target: &ArtifactId) -> Result { + let (path, sensitive_path) = MultiChainSequence::get_paths( + &config.broadcast, + &config.cache_path, + sig, + target, + true, + )?; + let mut sequence: MultiChainSequence = foundry_compilers::utils::read_json_file(&path) + .wrap_err("Multi-chain deployment not found.")?; + let sensitive_sequence: SensitiveMultiChainSequence = + foundry_compilers::utils::read_json_file(&sensitive_path) + .wrap_err("Multi-chain deployment sensitive details not found.")?; + + sequence.deployments.iter_mut().enumerate().for_each(|(i, sequence)| { + sequence.fill_sensitive(&sensitive_sequence.deployments[i]); + }); + + sequence.path = path; + sequence.sensitive_path = sensitive_path; + + Ok(sequence) } /// Saves the transactions as file if it's a standalone deployment. pub fn save(&mut self) -> Result<()> { self.timestamp = now().as_secs(); + let sensitive_sequence: SensitiveMultiChainSequence = self.into(); + + // broadcast writes //../Contract-latest/run.json let mut writer = BufWriter::new(fs::create_file(&self.path)?); serde_json::to_writer_pretty(&mut writer, &self)?; @@ -99,7 +154,20 @@ impl MultiChainSequence { fs::create_dir_all(file.parent().unwrap())?; fs::copy(&self.path, &file)?; + // cache writes + //../Contract-latest/run.json + let mut writer = BufWriter::new(fs::create_file(&self.sensitive_path)?); + serde_json::to_writer_pretty(&mut writer, &sensitive_sequence)?; + writer.flush()?; + + //../Contract-[timestamp]/run.json + let path = self.sensitive_path.to_string_lossy(); + let file = PathBuf::from(&path.replace("-latest", &format!("-{}", self.timestamp))); + fs::create_dir_all(file.parent().unwrap())?; + fs::copy(&self.sensitive_path, &file)?; + println!("\nTransactions saved to: {}\n", self.path.display()); + println!("Sensitive details saved to: {}\n", self.sensitive_path.display()); Ok(()) } diff --git a/crates/forge/bin/cmd/script/sequence.rs b/crates/forge/bin/cmd/script/sequence.rs index 62068aaf4fbd..6b6eb4acacb8 100644 --- a/crates/forge/bin/cmd/script/sequence.rs +++ b/crates/forge/bin/cmd/script/sequence.rs @@ -136,11 +136,7 @@ impl ScriptSequence { "Deployment's sensitive details not found for chain `{chain_id}`." ))?; - script_sequence - .transactions - .iter_mut() - .enumerate() - .for_each(|(i, tx)| tx.rpc = sensitive_script_sequence.transactions[i].rpc.clone()); + script_sequence.fill_sensitive(&sensitive_script_sequence); script_sequence.path = path; script_sequence.sensitive_path = sensitive_path; @@ -366,6 +362,13 @@ impl ScriptSequence { }) .collect() } + + pub fn fill_sensitive(&mut self, sensitive: &SensitiveScriptSequence) { + self.transactions + .iter_mut() + .enumerate() + .for_each(|(i, tx)| tx.rpc = sensitive.transactions[i].rpc.clone()); + } } impl Drop for ScriptSequence { @@ -379,7 +382,7 @@ impl Drop for ScriptSequence { /// /// This accepts either the signature of the function or the raw calldata -fn sig_to_file_name(sig: &str) -> String { +pub fn sig_to_file_name(sig: &str) -> String { if let Some((name, _)) = sig.split_once('(') { // strip until call argument parenthesis return name.to_string() From f2a5268462d8f6e8357462304a9f2cf226476b01 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 8 Dec 2023 18:23:42 +0400 Subject: [PATCH 3/3] Change to function --- crates/forge/bin/cmd/script/multi.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/forge/bin/cmd/script/multi.rs b/crates/forge/bin/cmd/script/multi.rs index 1c53229a24f2..a412ca453426 100644 --- a/crates/forge/bin/cmd/script/multi.rs +++ b/crates/forge/bin/cmd/script/multi.rs @@ -35,11 +35,9 @@ pub struct SensitiveMultiChainSequence { pub deployments: Vec, } -impl From<&mut MultiChainSequence> for SensitiveMultiChainSequence { - fn from(sequence: &mut MultiChainSequence) -> Self { - SensitiveMultiChainSequence { - deployments: sequence.deployments.iter_mut().map(|sequence| sequence.into()).collect(), - } +fn to_sensitive(sequence: &mut MultiChainSequence) -> SensitiveMultiChainSequence { + SensitiveMultiChainSequence { + deployments: sequence.deployments.iter_mut().map(|sequence| sequence.into()).collect(), } } @@ -140,7 +138,7 @@ impl MultiChainSequence { pub fn save(&mut self) -> Result<()> { self.timestamp = now().as_secs(); - let sensitive_sequence: SensitiveMultiChainSequence = self.into(); + let sensitive_sequence: SensitiveMultiChainSequence = to_sensitive(self); // broadcast writes //../Contract-latest/run.json