Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile contract artifacts in test targets #1585

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

maciektr
Copy link
Contributor

@maciektr maciektr commented Sep 9, 2024

  • Refactor starknet-contract compiler
  • Emit starknet contracts in test targets

@maciektr maciektr force-pushed the maciektr/test-target branch 5 times, most recently from e2cf31d to 9619404 Compare September 18, 2024 07:33
@maciektr maciektr changed the title maciektr/test target Compile contract artifacts in test targets Sep 18, 2024
@maciektr maciektr marked this pull request as ready for review September 18, 2024 07:34
Copy link
Contributor

@wawel37 wawel37 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

scarb/src/compiler/compilers/starknet_contract.rs Outdated Show resolved Hide resolved
scarb/src/compiler/compilers/starknet_contract.rs Outdated Show resolved Hide resolved
scarb/src/core/manifest/target.rs Show resolved Hide resolved
@@ -74,6 +82,45 @@ impl Compiler for TestCompiler {
)?;
}

if starknet {
compile_contracts(test_crate_ids, target_dir, unit, db, ws)?;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, this does not search in all dependencies.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate on this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in https://foundry-rs.github.io/starknet-foundry/testing/contracts-collection.html?highlight=build-external#how-contracts-are-collected, Forge requires contracts defined in dependencies to be explicitly declared in manifest file, for them to be available in tests.

On the contrary, Cairo Test searches all dependencies (even not direct ones) for contracts and compiles all of them, without any explicit declaration. This might be sub-optimal in some cases, as contracts can be quite large (see: https://swmansion.slack.com/archives/C037B80988J/p1726501029482169).

this only searches for contracts in the main component of the compilation unit (so the package for unit tests, and the tests directory for integration tests) + ones declared in build-external-contracts.

scarb/src/core/manifest/target.rs Show resolved Hide resolved
scarb/src/compiler/compilers/starknet_contract.rs Outdated Show resolved Hide resolved
@@ -74,6 +82,45 @@ impl Compiler for TestCompiler {
)?;
}

if starknet {
compile_contracts(test_crate_ids, target_dir, unit, db, ws)?;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate on this?

};
let external_contracts = external_contracts
.into_iter()
.chain(vec![format!("{package_name}::*")])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason that this is not included earlier?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous target is a unit test one, so the tested package is the main component of the compilation unit. This means, that it will be searched for contracts as a main package (i.e. it's in test_crate_ids).

For the integration ones (below), the tested package is treated as any other dependency, so it's not in test_crate_ids and thus would not be searched for contracts, unless we explicitly ask for this.

We also can assume, that build-external-contracts does not include this package already, as it's defined in starknet-contract target of said package, thus is external to the package in question.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! As a nitpick this code can be placed further down for better readability, for example on line 702.

Copy link
Member

@cptartur cptartur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not verify the logic, but generated artefacts make sense to me.

Copy link
Contributor

@wawel37 wawel37 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tbh I don't understand all the logic behind this, but other than that looks good


impl ContractArtifacts {
fn new(
package_name: &PackageName,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: You can just move the variable here, as in the only function you're using the ContractArtifacts::new, you don't move the package_name anywhere else.

) -> Self {
Self {
id: short_hash((&package_name, &contract_path)),
package_name: package_name.clone(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If u decide to move package_name here, u will not have to clone it here

let mut artifacts = StarknetArtifacts::default();
let mut file_stem_calculator = ContractFileStemCalculator::new(contract_paths);

for (decl, class, casm_class) in izip!(contracts, classes, casm_classes) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's very nit, you can even ignore it, but this always catches my attention. Are You sure we want to use short trimmed names like decl instead of contract_declaration or declaration?

Comment on lines +105 to +109
let contract_name = decl.submodule_id.name(db.upcast_mut());
let contract_path = decl.module_id().full_path(db.upcast_mut());

let contract_selector = ContractSelector(contract_path);
let package_name = contract_selector.package();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the current implementation it seems that compiling a given conract with test and starknet-contract targets will produce artifacts with the same contract_name and package_name (and id as well?). Would it make sense to distinguish between these artifacts at this level, perhaps by appending unittest or integrationtest to the contract name?

Copy link
Contributor Author

@maciektr maciektr Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the contract names are not prepended by package name, but rather by the target name (

let file_stem = format!("{}_{contract_stem}", self.target_name);
).
image

But technically it's true, that it can be overwritten! Thanks for pointing this out!
We only ensure uniqueness of pairs (target_name, target_kind), not target_name only - so if someone provides test targets manually in the manifest, it would be possible to make a conflict. Of course it's a very esoteric case, but still.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants