Repository navigation
Compile factory dependencies that are only present as nested Yul objects #648
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
base: main
Are you sure you want to change the base?
Changes from all commits
1020434
2aa2eb7
6d48094
2bb2c20
68c1408
351dfdc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,22 +49,51 @@ pub struct Project { | |
|
|
||
| impl Project { | ||
| /// A shortcut constructor. | ||
| /// | ||
| /// Nested factory dependency objects not otherwise part of `contracts` are added as contracts. | ||
| /// A nested object whose path is already taken by another contract is an error. | ||
| pub fn new( | ||
| version: Option<SolcVersion>, | ||
| contracts: BTreeMap<String, Contract>, | ||
| mut contracts: BTreeMap<String, Contract>, | ||
| libraries: SolcStandardJsonInputSettingsLibraries, | ||
| ) -> Self { | ||
| ) -> anyhow::Result<Self> { | ||
| let mut identifier_paths = BTreeMap::new(); | ||
| for (path, contract) in contracts.iter() { | ||
| identifier_paths.insert(contract.object_identifier().to_owned(), path.to_owned()); | ||
| } | ||
|
|
||
| Self { | ||
| let mut unresolved_contracts: Vec<Contract> = contracts | ||
| .values() | ||
| .flat_map(|contract| contract.unresolved_factory_dependencies(&identifier_paths)) | ||
| .collect(); | ||
| while let Some(contract) = unresolved_contracts.pop() { | ||
| if identifier_paths.contains_key(contract.object_identifier()) { | ||
| continue; | ||
| } | ||
| if contracts.contains_key(contract.identifier.full_path.as_str()) { | ||
| anyhow::bail!( | ||
| "the nested object `{}` can not be emitted as `{}`, which is the path of another \ | ||
| contract. Adding the source file of `{}` to the output selection avoids this.", | ||
| contract.object_identifier(), | ||
| contract.identifier.full_path, | ||
| contract.object_identifier(), | ||
| ); | ||
| } | ||
| identifier_paths.insert( | ||
| contract.object_identifier().to_owned(), | ||
| contract.identifier.full_path.to_owned(), | ||
| ); | ||
| unresolved_contracts | ||
| .extend(contract.unresolved_factory_dependencies(&identifier_paths)); | ||
| contracts.insert(contract.identifier.full_path.to_owned(), contract); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A resolved contract will have the key This example shows how there can be 2 different contracts getting the key Example:
Output {"language":"Solidity","sources":{"A.sol":{"content":"contract K { uint256 public v = 7; }"},"B.sol":{"content":"import \"A.sol\"; contract K_4 { function w() external pure returns (uint256) { return 42; } } contract P { function mk() external returns (address) { return address(new K()); } function mk4() external returns (address) { return address(new K_4()); } }"}},"settings":{"optimizer":{"enabled":true},"outputSelection":{"B.sol":{"*":["evm.bytecode"]}}}}
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch thanks. Just errors out now
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is still unresolved. For instance, you can compare the previous JSON repro (which selects only
{"language":"Solidity","sources":{"A.sol":{"content":"contract K { uint256 public v = 7; }"},"B.sol":{"content":"import \"A.sol\"; contract K_4 { function w() external pure returns (uint256) { return 42; } } contract P { function mk() external returns (address) { return address(new K()); } function mk4() external returns (address) { return address(new K_4()); } }"}},"settings":{"optimizer":{"enabled":true},"outputSelection":{"B.sol":{"*":["evm.bytecode"]}}}}
{"language":"Solidity","sources":{"A.sol":{"content":"contract K { uint256 public v = 7; }"},"B.sol":{"content":"import \"A.sol\"; contract K_4 { function w() external pure returns (uint256) { return 42; } } contract P { function mk() external returns (address) { return address(new K()); } function mk4() external returns (address) { return address(new K_4()); } }"}},"settings":{"optimizer":{"enabled":true},"outputSelection":{"A.sol":{"*":["evm.bytecode"]},"B.sol":{"*":["evm.bytecode"]}}}}for input in repro.json repro-all.json; do
resolc --standard-json < $input | jq -c '.contracts | {"A.sol:K": .["A.sol"].K.hash[0:8], "B.sol:K_4": .["B.sol"].K_4.hash[0:8]}'
done
# Output (solc v0.8.36 used):
# {"A.sol:K":null,"B.sol:K_4":"55af49df"}
# {"A.sol:K":"55af49df","B.sol:K_4":"b96a268a"}With both files selected (second output row), it shows that Possible fix (reaches the error from #600):
while let Some(contract) = unresolved_contracts.pop() {
- if identifier_paths.contains_key(contract.object_identifier()) {
+ if identifier_paths.contains_key(contract.object_identifier())
+ || contracts.contains_key(&contract.identifier.full_path)
+ {
continue;
} |
||
| } | ||
|
|
||
| Ok(Self { | ||
| version, | ||
| contracts, | ||
| identifier_paths, | ||
| libraries, | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| /// Compiles all contracts, returning their build artifacts. | ||
|
|
@@ -175,7 +204,7 @@ impl Project { | |
| contract | ||
| .ir | ||
| .factory_dependencies() | ||
| .iter() | ||
| .keys() | ||
| .filter_map(|identifier| self.identifier_paths.get(identifier)) | ||
| .map(String::as_str), | ||
| ); | ||
|
|
@@ -259,7 +288,7 @@ impl Project { | |
| }, | ||
| } | ||
| } | ||
| Ok(Self::new(None, contracts, libraries)) | ||
| Self::new(None, contracts, libraries) | ||
| } | ||
|
|
||
| /// Converts the `solc` JSON output into a convenient project. | ||
|
|
@@ -310,11 +339,7 @@ impl Project { | |
| Err(error) => solc_output.push_error(Some(path), error), | ||
| } | ||
| } | ||
| Ok(Project::new( | ||
| Some(solc_version.clone()), | ||
| contracts, | ||
| libraries, | ||
| )) | ||
| Project::new(Some(solc_version.clone()), contracts, libraries) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| contract K { uint256 public v = 7; } | ||
| contract P { function mk() external returns (address) { return address(new K()); } } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"language":"Solidity","sources":{"A.sol":{"content":"import \"B.sol\"; contract P { function mk() external returns (address) { return address(new K()); } }"},"B.sol":{"content":"contract K { uint256 public v = 7; }"}},"settings":{"optimizer":{"enabled":true},"outputSelection":{"A.sol":{"*":["evm.bytecode"]}}}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"language":"Solidity","sources":{"A.sol":{"content":"import \"B.sol\"; contract P { function mk() external returns (address) { return address(new K()); } }"},"B.sol":{"content":"library L { function f(uint256 x) external pure returns (uint256) { return x * 3; } } contract K { function g(uint256 x) external pure returns (uint256) { return L.f(x); } }"}},"settings":{"optimizer":{"enabled":true},"outputSelection":{"A.sol":{"*":["evm.bytecode"]}}}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"language":"Solidity","sources":{"A.sol":{"content":"contract K { uint256 public v = 7; }"},"B.sol":{"content":"import \"A.sol\"; contract K_4 { function w() external pure returns (uint256) { return 42; } } contract P { function mk() external returns (address) { return address(new K()); } function mk4() external returns (address) { return address(new K_4()); } }"}},"settings":{"optimizer":{"enabled":true},"outputSelection":{"B.sol":{"*":["evm.bytecode"]}}}} |
Uh oh!
There was an error while loading. Please reload this page.