From 102e680b699618746fcd422a386bdbbd7badbcff Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 25 Mar 2021 06:03:14 +0100 Subject: [PATCH 1/4] Detect version mismatches of `parity-scale-codec` --- src/cmd/build.rs | 66 ++++++++++++++++++++++++++++++++++++++- src/workspace/manifest.rs | 18 +++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index abef85ef..56fdc848 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -430,6 +430,21 @@ fn do_optimization( Ok(()) } +/// Asserts that the contract's dependencies are compatible to the ones used in ink!. +/// +/// This function utilizes `cargo tree`, which takes semver into consideration. +/// Hence this function only returns an `Err` if it is a proper mismatch in the +/// major version, and not if the versions mismatch on the minor/patch version. +fn assert_compatible_ink_dependencies( + manifest_path: &ManifestPath, + verbosity: Verbosity, +) -> Result<()> { + let args = ["-i=parity-scale-codec", "--duplicates"]; + util::invoke_cargo("tree", &args, manifest_path.directory(), verbosity) + .map(|_| ()) + .map_err(|_| anyhow::anyhow!("Mismatching versions of `parity-scale-codec` were found!")) +} + /// Executes build of the smart-contract which produces a wasm binary that is ready for deploying. /// /// It does so by invoking `cargo build` and then post processing the final binary. @@ -440,7 +455,9 @@ pub(crate) fn execute( unstable_flags: UnstableFlags, optimization_passes: OptimizationPasses, ) -> Result { - let crate_metadata = CrateMetadata::collect(manifest_path)?; + let crate_metadata = CrateMetadata::collect(&manifest_path)?; + + assert_compatible_ink_dependencies(&manifest_path, verbosity)?; let build = || -> Result { maybe_println!( @@ -506,6 +523,7 @@ pub(crate) fn execute( #[cfg(feature = "test-ci-only")] #[cfg(test)] mod tests_ci_only { + use super::assert_compatible_ink_dependencies; use crate::{ cmd::{self, BuildCommand}, util::tests::with_tmp_dir, @@ -626,4 +644,50 @@ mod tests_ci_only { Ok(()) }) } + + #[test] + fn project_template_dependencies_must_be_ink_compatible() { + with_tmp_dir(|path| { + // given + cmd::new::execute("new_project", Some(path)).expect("new project creation failed"); + let cargo_toml_path = path.join("new_project").join("Cargo.toml"); + let manifest_path = + ManifestPath::new(&cargo_toml_path).expect("manifest path creation failed"); + + // when + let res = assert_compatible_ink_dependencies(&manifest_path, Verbosity::Default); + + // then + assert!(res.is_ok()); + Ok(()) + }) + } + + #[test] + fn detect_mismatching_parity_scale_codec_dependencies() { + with_tmp_dir(|path| { + // given + cmd::new::execute("new_project", Some(path)).expect("new project creation failed"); + let cargo_toml_path = path.join("new_project").join("Cargo.toml"); + let manifest_path = + ManifestPath::new(&cargo_toml_path).expect("manifest path creation failed"); + + // at the time of writing this test ink! already uses `parity-scale-codec` + // in a version > 2, hence 1 is an incompatible version. + let mut manifest = Manifest::new(manifest_path.clone())?; + manifest + .set_dependency_version("scale", "1.0.0") + .expect("setting `scale` version failed"); + manifest + .write(&manifest_path) + .expect("writing manifest failed"); + + // when + let res = assert_compatible_ink_dependencies(&manifest_path, Verbosity::Default); + + // then + assert!(res.is_err()); + Ok(()) + }) + } } diff --git a/src/workspace/manifest.rs b/src/workspace/manifest.rs index ce44c030..5a439926 100644 --- a/src/workspace/manifest.rs +++ b/src/workspace/manifest.rs @@ -204,6 +204,24 @@ impl Manifest { )) } + /// Set the dependency version of `package` to `version`. + #[cfg(test)] + pub fn set_dependency_version( + &mut self, + dependency: &str, + version: &str, + ) -> Result> { + Ok(self + .toml + .get_mut("dependencies") + .ok_or_else(|| anyhow::anyhow!("[dependencies] section not found"))? + .get_mut(dependency) + .ok_or_else(|| anyhow::anyhow!("{} dependency not found", dependency))? + .as_table_mut() + .ok_or_else(|| anyhow::anyhow!("{} dependency should be a table", dependency))? + .insert("version".into(), value::Value::String(version.into()))) + } + /// Set `[profile.release]` lto flag pub fn with_profile_release_lto(&mut self, enabled: bool) -> Result<&mut Self> { let lto = self -- GitLab From 258ef841588ed0e85619a265e6e227cee8adb037 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 25 Mar 2021 11:08:43 +0100 Subject: [PATCH 2/4] Detect `scale-info` mismatch as well --- src/cmd/build.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 56fdc848..9fd58d60 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -439,10 +439,12 @@ fn assert_compatible_ink_dependencies( manifest_path: &ManifestPath, verbosity: Verbosity, ) -> Result<()> { - let args = ["-i=parity-scale-codec", "--duplicates"]; - util::invoke_cargo("tree", &args, manifest_path.directory(), verbosity) - .map(|_| ()) - .map_err(|_| anyhow::anyhow!("Mismatching versions of `parity-scale-codec` were found!")) + for dependency in ["parity-scale-codec", "scale-info"].iter() { + let args = ["-i", dependency, "--duplicates"]; + let _ = util::invoke_cargo("tree", &args, manifest_path.directory(), verbosity) + .map_err(|_| anyhow::anyhow!("Mismatching versions of `{}` were found!", dependency))?; + } + Ok(()) } /// Executes build of the smart-contract which produces a wasm binary that is ready for deploying. -- GitLab From 745c477dbb9dad5fe91d13888c92fe8f9b07b124 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 26 Mar 2021 07:42:04 +0100 Subject: [PATCH 3/4] Improve error message --- src/cmd/build.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 9fd58d60..290661dd 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -441,8 +441,16 @@ fn assert_compatible_ink_dependencies( ) -> Result<()> { for dependency in ["parity-scale-codec", "scale-info"].iter() { let args = ["-i", dependency, "--duplicates"]; - let _ = util::invoke_cargo("tree", &args, manifest_path.directory(), verbosity) - .map_err(|_| anyhow::anyhow!("Mismatching versions of `{}` were found!", dependency))?; + let _ = util::invoke_cargo("tree", &args, manifest_path.directory(), verbosity).map_err( + |_| { + anyhow::anyhow!( + "Mismatching versions of `{}` were found!\n\ + Please ensure that your contract and your ink! dependency use a compatible \ + version of this package.", + dependency + ) + }, + )?; } Ok(()) } -- GitLab From 7d352c16cc54454a2dd68de700dec36950358a86 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 26 Mar 2021 08:13:04 +0100 Subject: [PATCH 4/4] Clarify when a mismatch happens --- src/cmd/build.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 290661dd..f04cc955 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -433,8 +433,13 @@ fn do_optimization( /// Asserts that the contract's dependencies are compatible to the ones used in ink!. /// /// This function utilizes `cargo tree`, which takes semver into consideration. -/// Hence this function only returns an `Err` if it is a proper mismatch in the -/// major version, and not if the versions mismatch on the minor/patch version. +/// +/// Hence this function only returns an `Err` if it is a proper mismatch according +/// to semantic versioning. This means that either: +/// - the major version mismatches, differences in the minor/patch version +/// are not considered incompatible. +/// - or if the version starts with zero (i.e. `0.y.z`) a mismatch in the minor +/// version is already considered incompatible. fn assert_compatible_ink_dependencies( manifest_path: &ManifestPath, verbosity: Verbosity, @@ -445,7 +450,7 @@ fn assert_compatible_ink_dependencies( |_| { anyhow::anyhow!( "Mismatching versions of `{}` were found!\n\ - Please ensure that your contract and your ink! dependency use a compatible \ + Please ensure that your contract and your ink! dependencies use a compatible \ version of this package.", dependency ) -- GitLab