From 89edb5f963507aa55a8ffba71f82b3947919144f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 28 Feb 2023 10:15:39 +0000 Subject: [PATCH 01/12] Read workspace members for additional contracts --- crates/e2e/macro/Cargo.toml | 1 + crates/e2e/macro/src/codegen.rs | 49 +++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/crates/e2e/macro/Cargo.toml b/crates/e2e/macro/Cargo.toml index 0292f23b71..2f88031c3a 100644 --- a/crates/e2e/macro/Cargo.toml +++ b/crates/e2e/macro/Cargo.toml @@ -20,6 +20,7 @@ proc-macro = true [dependencies] ink_ir = { version = "4.0.1", path = "../../ink/ir" } +cargo_metadata = "0.15.3" contract-build = "2.0.0" derive_more = "0.99.17" env_logger = "0.10.0" diff --git a/crates/e2e/macro/src/codegen.rs b/crates/e2e/macro/src/codegen.rs index 5286739f0f..d205d6628f 100644 --- a/crates/e2e/macro/src/codegen.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -78,11 +78,19 @@ impl InkE2ETest { .environment() .unwrap_or_else(|| syn::parse_quote! { ::ink::env::DefaultEnvironment }); - let mut additional_contracts: Vec = - self.test.config.additional_contracts(); - let default_main_contract_manifest_path = String::from("Cargo.toml"); - let mut contracts_to_build_and_import = vec![default_main_contract_manifest_path]; - contracts_to_build_and_import.append(&mut additional_contracts); + let contracts_to_build_and_import = + if self.test.config.additional_contracts().is_empty() { + workspace_contract_manifests() + } else { + // backwards compatibility if `additional_contracts` specified + let mut additional_contracts: Vec = + self.test.config.additional_contracts(); + let default_main_contract_manifest_path = String::from("Cargo.toml"); + let mut contracts_to_build_and_import = + vec![default_main_contract_manifest_path]; + contracts_to_build_and_import.append(&mut additional_contracts); + contracts_to_build_and_import + }; let mut already_built_contracts = already_built_contracts(); if already_built_contracts.is_empty() { @@ -188,6 +196,37 @@ impl InkE2ETest { } } +/// Returns a list of manifests of workspace members which are inferred to be `ink!` contracts. +/// +/// It is assumed that an `ink!` contract will have the `ink-as-dependency` feature specified. +fn workspace_contract_manifests() -> Vec { + let cmd = cargo_metadata::MetadataCommand::new(); + let metadata = cmd + .exec() + .unwrap_or_else(|err| panic!("Error invoking `cargo metadata`: {:?}", err)); + metadata + .workspace_members + .iter() + .filter_map(|workspace_member| { + let package = metadata + .packages + .iter() + .find(|package| &package.id == workspace_member) + .unwrap_or_else(|| { + panic!( + "Failed to find workspace member package '{}'", + workspace_member + ) + }); + package + .features + .iter() + .any(|(feat, _)| feat == "ink-as-dependency") + .then(|| package.manifest_path.to_string()) + }) + .collect() +} + /// Builds the contract at `manifest_path`, returns the path to the contract /// bundle build artifact. fn build_contract(path_to_cargo_toml: &str) -> String { From c8dc85f7f45890daf02a9f35a80e8ebe255d606d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 1 Mar 2023 17:50:23 +0000 Subject: [PATCH 02/12] Upgrade requirement for `contract-build` to `2.0.2` --- crates/e2e/macro/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/e2e/macro/Cargo.toml b/crates/e2e/macro/Cargo.toml index 2f88031c3a..14601e90c2 100644 --- a/crates/e2e/macro/Cargo.toml +++ b/crates/e2e/macro/Cargo.toml @@ -21,7 +21,7 @@ proc-macro = true [dependencies] ink_ir = { version = "4.0.1", path = "../../ink/ir" } cargo_metadata = "0.15.3" -contract-build = "2.0.0" +contract-build = "2.0.2" derive_more = "0.99.17" env_logger = "0.10.0" log = "0.4.17" From 24358e05295f07232c234f688939e5296d10a0c7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 2 Mar 2023 10:18:03 +0000 Subject: [PATCH 03/12] Change to using CrateMetadata of the current package to determine contract dependencies --- crates/e2e/macro/src/codegen.rs | 83 +++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/crates/e2e/macro/src/codegen.rs b/crates/e2e/macro/src/codegen.rs index e4347bd962..6d51b64fc1 100644 --- a/crates/e2e/macro/src/codegen.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -13,6 +13,7 @@ // limitations under the License. use crate::ir; +use contract_build::ManifestPath; use core::cell::RefCell; use derive_more::From; use proc_macro2::TokenStream as TokenStream2; @@ -78,16 +79,17 @@ impl InkE2ETest { .environment() .unwrap_or_else(|| syn::parse_quote! { ::ink::env::DefaultEnvironment }); + let contract_manifests = ContractManifests::from_crate_metadata(); + let contracts_to_build_and_import = if self.test.config.additional_contracts().is_empty() { - workspace_contract_manifests() + contract_manifests.all_contracts_to_build() } else { // backwards compatibility if `additional_contracts` specified let mut additional_contracts: Vec = self.test.config.additional_contracts(); - let default_main_contract_manifest_path = String::from("Cargo.toml"); - let mut contracts_to_build_and_import = - vec![default_main_contract_manifest_path]; + let mut contracts_to_build_and_import: Vec = + contract_manifests.root_package.iter().cloned().collect(); contracts_to_build_and_import.append(&mut additional_contracts); contracts_to_build_and_import }; @@ -196,35 +198,59 @@ impl InkE2ETest { } } -/// Returns a list of manifests of workspace members which are inferred to be `ink!` contracts. -/// -/// It is assumed that an `ink!` contract will have the `ink-as-dependency` feature specified. -fn workspace_contract_manifests() -> Vec { - let cmd = cargo_metadata::MetadataCommand::new(); - let metadata = cmd - .exec() - .unwrap_or_else(|err| panic!("Error invoking `cargo metadata`: {:?}", err)); - metadata - .workspace_members - .iter() - .filter_map(|workspace_member| { - let package = metadata - .packages - .iter() - .find(|package| &package.id == workspace_member) - .unwrap_or_else(|| { - panic!( - "Failed to find workspace member package '{}'", - workspace_member - ) - }); +#[derive(Debug)] +struct ContractManifests { + /// The manifest path of the root package where the e2e test is defined. + /// `None` if the root package is not an `ink!` contract definition. + root_package: Option, + /// The manifest paths of any dependencies which are `ink!` contracts. + contract_dependencies: Vec, +} + +impl ContractManifests { + /// Load any manifests for packages which are detected to be `ink!` contracts. Any package + /// with the `ink-as-dependency` feature enabled is assumed to be an `ink!` contract. + fn from_crate_metadata() -> Self { + let manifest_path = ManifestPath::default(); + let crate_metadata = contract_build::CrateMetadata::collect(&manifest_path) + .unwrap_or_else(|err| { + panic!( + "Error loading crate metadata for '{}': {}", + manifest_path.as_ref().display(), + err + ) + }); + + fn maybe_contract_package(package: &cargo_metadata::Package) -> Option { package .features .iter() .any(|(feat, _)| feat == "ink-as-dependency") .then(|| package.manifest_path.to_string()) - }) - .collect() + } + + let root_package = maybe_contract_package(&crate_metadata.root_package); + + let contract_dependencies = crate_metadata + .cargo_meta + .packages + .iter() + .filter_map(maybe_contract_package) + .collect(); + + Self { + root_package, + contract_dependencies, + } + } + + /// Returns all the contract manifests which are to be built, including the root package + /// if it is determined to be an `ink!` contract. + fn all_contracts_to_build(&self) -> Vec { + let mut all_manifests: Vec = self.root_package.iter().cloned().collect(); + all_manifests.append(&mut self.contract_dependencies.clone()); + all_manifests + } } /// Builds the contract at `manifest_path`, returns the path to the contract @@ -235,7 +261,6 @@ fn build_contract(path_to_cargo_toml: &str) -> String { BuildMode, ExecuteArgs, Features, - ManifestPath, Network, OptimizationPasses, OutputType, From 1c251bf4b9059ef332080b585ca0354340d563d0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 2 Mar 2023 10:19:08 +0000 Subject: [PATCH 04/12] Add comment --- crates/e2e/macro/src/codegen.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/e2e/macro/src/codegen.rs b/crates/e2e/macro/src/codegen.rs index 6d51b64fc1..355fb919fc 100644 --- a/crates/e2e/macro/src/codegen.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -211,6 +211,8 @@ impl ContractManifests { /// Load any manifests for packages which are detected to be `ink!` contracts. Any package /// with the `ink-as-dependency` feature enabled is assumed to be an `ink!` contract. fn from_crate_metadata() -> Self { + // The default manifest path is the `Cargo.toml` in the current directory. + // So in this case the package within which the E2E test is defined. let manifest_path = ManifestPath::default(); let crate_metadata = contract_build::CrateMetadata::collect(&manifest_path) .unwrap_or_else(|err| { From 243204186397172a18402a11a870049d113a2139 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 2 Mar 2023 10:21:31 +0000 Subject: [PATCH 05/12] Modify check for additional contracts to check for not already build contract. --- crates/e2e/macro/src/codegen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/e2e/macro/src/codegen.rs b/crates/e2e/macro/src/codegen.rs index 355fb919fc..2a7372d886 100644 --- a/crates/e2e/macro/src/codegen.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -110,7 +110,7 @@ impl InkE2ETest { // `additional_contracts` for this particular test contain ones // that haven't been build before for manifest_path in contracts_to_build_and_import { - if already_built_contracts.get("Cargo.toml").is_none() { + if already_built_contracts.get(&manifest_path).is_none() { let dest_wasm = build_contract(&manifest_path); let _ = already_built_contracts.insert(manifest_path, dest_wasm); } From 0e7813fdfcfb6c8fac1a50e9711b64e4d574b88e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 2 Mar 2023 10:27:18 +0000 Subject: [PATCH 06/12] Removed additional_contracts annotations from call_builder example --- .../call-builder/lib.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/integration-tests/lang-err-integration-tests/call-builder/lib.rs b/integration-tests/lang-err-integration-tests/call-builder/lib.rs index 092ad1d035..d2562bb1ff 100755 --- a/integration-tests/lang-err-integration-tests/call-builder/lib.rs +++ b/integration-tests/lang-err-integration-tests/call-builder/lib.rs @@ -166,9 +166,7 @@ mod call_builder { type E2EResult = std::result::Result>; - #[ink_e2e::test( - additional_contracts = "../integration-flipper/Cargo.toml ../constructors-return-value/Cargo.toml" - )] + #[ink_e2e::test] async fn e2e_invalid_message_selector_can_be_handled( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -221,7 +219,7 @@ mod call_builder { Ok(()) } - #[ink_e2e::test(additional_contracts = "../integration-flipper/Cargo.toml")] + #[ink_e2e::test] async fn e2e_invalid_message_selector_panics_on_invoke( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -258,7 +256,7 @@ mod call_builder { Ok(()) } - #[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")] + #[ink_e2e::test] async fn e2e_create_builder_works_with_valid_selector( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -299,7 +297,7 @@ mod call_builder { Ok(()) } - #[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")] + #[ink_e2e::test] async fn e2e_create_builder_fails_with_invalid_selector( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -340,7 +338,7 @@ mod call_builder { Ok(()) } - #[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")] + #[ink_e2e::test] async fn e2e_create_builder_with_infallible_revert_constructor_encodes_ok( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -385,7 +383,7 @@ mod call_builder { Ok(()) } - #[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")] + #[ink_e2e::test] async fn e2e_create_builder_can_handle_fallible_constructor_success( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -426,7 +424,7 @@ mod call_builder { Ok(()) } - #[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")] + #[ink_e2e::test] async fn e2e_create_builder_can_handle_fallible_constructor_error( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -474,7 +472,7 @@ mod call_builder { Ok(()) } - #[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")] + #[ink_e2e::test] async fn e2e_create_builder_with_fallible_revert_constructor_encodes_ok( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -519,7 +517,7 @@ mod call_builder { Ok(()) } - #[ink_e2e::test(additional_contracts = "../constructors-return-value/Cargo.toml")] + #[ink_e2e::test] async fn e2e_create_builder_with_fallible_revert_constructor_encodes_err( mut client: ink_e2e::Client, ) -> E2EResult<()> { From 9135e9d4302e3c13cfafaadbad4114e66517f3cc Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 2 Mar 2023 10:32:29 +0000 Subject: [PATCH 07/12] Removed additional_contracts annotations from contract_ref example --- .../lang-err-integration-tests/contract-ref/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/lang-err-integration-tests/contract-ref/lib.rs b/integration-tests/lang-err-integration-tests/contract-ref/lib.rs index 963722d79d..f046ca821f 100755 --- a/integration-tests/lang-err-integration-tests/contract-ref/lib.rs +++ b/integration-tests/lang-err-integration-tests/contract-ref/lib.rs @@ -72,7 +72,7 @@ mod contract_ref { type E2EResult = std::result::Result>; - #[ink_e2e::test(additional_contracts = "../integration-flipper/Cargo.toml")] + #[ink_e2e::test] async fn e2e_ref_can_flip_correctly( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -117,7 +117,7 @@ mod contract_ref { Ok(()) } - #[ink_e2e::test(additional_contracts = "../integration-flipper/Cargo.toml")] + #[ink_e2e::test] async fn e2e_fallible_ref_can_be_instantiated( mut client: ink_e2e::Client, ) -> E2EResult<()> { @@ -147,7 +147,7 @@ mod contract_ref { Ok(()) } - #[ink_e2e::test(additional_contracts = "../integration-flipper/Cargo.toml")] + #[ink_e2e::test] async fn e2e_fallible_ref_fails_to_be_instantiated( mut client: ink_e2e::Client, ) -> E2EResult<()> { From dacb4d3695cb7adaf018d72c6624a7fca797ddcb Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 2 Mar 2023 10:34:11 +0000 Subject: [PATCH 08/12] Removed additional_contracts annotations from delegator example --- integration-tests/delegator/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/integration-tests/delegator/lib.rs b/integration-tests/delegator/lib.rs index 880c3dcbd8..97e0c7de0e 100644 --- a/integration-tests/delegator/lib.rs +++ b/integration-tests/delegator/lib.rs @@ -118,9 +118,7 @@ mod delegator { type E2EResult = std::result::Result>; - #[ink_e2e::test( - additional_contracts = "accumulator/Cargo.toml adder/Cargo.toml subber/Cargo.toml" - )] + #[ink_e2e::test] async fn e2e_delegator(mut client: ink_e2e::Client) -> E2EResult<()> { // given let accumulator_hash = client From 483b98e2f3e5b9088789ea199b86457d6afa024f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 2 Mar 2023 10:51:19 +0000 Subject: [PATCH 09/12] Add help to error message when contract not found --- crates/e2e/src/client.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/e2e/src/client.rs b/crates/e2e/src/client.rs index 74735a9b6f..a359b4f313 100644 --- a/crates/e2e/src/client.rs +++ b/crates/e2e/src/client.rs @@ -494,7 +494,14 @@ where let wasm_path = self .contracts .get(&contract.replace('-', "_")) - .unwrap_or_else(|| panic!("Unknown contract {contract}")); + .unwrap_or_else(|| + panic!( + "Unknown contract {contract}. Available contracts: {:?}.\n\ + For a contract to be built, add as a dependency to the `Cargo.toml`, or add \ + the manifest path to `#[ink_e2e::test(additional_contracts = ..)]`", + self.contracts.keys() + ) + ); let code = std::fs::read(wasm_path).unwrap_or_else(|err| { panic!("Error loading '{}': {:?}", wasm_path.display(), err) }); From a85f59204b6f65f63f030c54a64747d5c9f35c11 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 2 Mar 2023 10:53:37 +0000 Subject: [PATCH 10/12] Spellcheck --- crates/e2e/macro/src/codegen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/e2e/macro/src/codegen.rs b/crates/e2e/macro/src/codegen.rs index 2a7372d886..046f35c8e1 100644 --- a/crates/e2e/macro/src/codegen.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -200,7 +200,7 @@ impl InkE2ETest { #[derive(Debug)] struct ContractManifests { - /// The manifest path of the root package where the e2e test is defined. + /// The manifest path of the root package where the E2E test is defined. /// `None` if the root package is not an `ink!` contract definition. root_package: Option, /// The manifest paths of any dependencies which are `ink!` contracts. From dabe4a1c57ad7ccfa9dbe79307f228a910a88f8e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 3 Mar 2023 17:06:38 +0000 Subject: [PATCH 11/12] Update crates/e2e/src/client.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michael Müller --- crates/e2e/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/e2e/src/client.rs b/crates/e2e/src/client.rs index a359b4f313..b92419311c 100644 --- a/crates/e2e/src/client.rs +++ b/crates/e2e/src/client.rs @@ -497,7 +497,7 @@ where .unwrap_or_else(|| panic!( "Unknown contract {contract}. Available contracts: {:?}.\n\ - For a contract to be built, add as a dependency to the `Cargo.toml`, or add \ + For a contract to be built, add it as a dependency to the `Cargo.toml`, or add \ the manifest path to `#[ink_e2e::test(additional_contracts = ..)]`", self.contracts.keys() ) From 370120eacacae388215f6b228af05adf125e886b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 3 Mar 2023 17:08:39 +0000 Subject: [PATCH 12/12] CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17afca16c9..5f1cfc5409 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Basic support for `dyn Trait` to allow cross-contract calls only with trait - [#1673](https://github.com/paritytech/ink/pull/1673) +- E2E: auto detect contracts to be built - [#1691](https://github.com/paritytech/ink/pull/1691) ## Version 4.0.1