-
Notifications
You must be signed in to change notification settings - Fork 49
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
fix: create verifiable Standard JSON for projects with external files #36
fix: create verifiable Standard JSON for projects with external files #36
Conversation
``` $ cargo test --test project --all-features can_create_standard_json_input_with_external_file Finished test [unoptimized + debuginfo] target(s) in 0.10s Running tests/project.rs (target/debug/deps/project-bc070fde513cf057) running 1 test test can_create_standard_json_input_with_external_file ... FAILED failures: ---- can_create_standard_json_input_with_external_file stdout ---- thread 'can_create_standard_json_input_with_external_file' panicked at tests/project.rs:1649:5: assertion failed: `(left == right)` Diff < left / right > : [ "src/Counter.sol", "../remapped/Parent.sol", < "/private/var/folders/1m/9vppwqks3pz4btz9gnczfmgh0000gn/T/.tmpSWn2KX/remapped/Child.sol", > "../remapped/Child.sol", ] note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: can_create_standard_json_input_with_external_file test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 52 filtered out; finished in 1.38s error: test failed, to rerun pass `--test project` ```
let verif_dir = utils::canonicalize(dir.path()).unwrap().join("verif"); | ||
let remapped_dir = utils::canonicalize(dir.path()).unwrap().join("remapped"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After my previous PR is merged, this canonicalization can be removed. It is necessary on this branch because the symlink-resolving canonicalization is still in effect, and the temporary directory on macOS is a symlink.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
amazing, tysm!
as mentioned in the other PR, I'd like to see a foundry companion PR with patched crate dep as a sanity check before we merge this
Thank you for your review! I've created a companion PR in foundry with this patch. Also, I have confirmed that the tests in foundry passed successfully. |
The workflow test for this PR failed due to a failure in nextest installation. As this issue is unrelated to the changes made, re-running the test should resolve it. https://github.com/foundry-rs/compilers/actions/runs/7331166894/job/19979490471 |
src/lib.rs
Outdated
for (i, (base_component, path_component)) in | ||
base.components().zip(path.components()).enumerate() | ||
{ | ||
if base_component == path_component { | ||
new_path.pop_front(); | ||
} else { | ||
let mut parent_dirs = | ||
vec![std::path::Component::ParentDir; base.components().count() - i]; | ||
parent_dirs.extend(new_path); | ||
new_path = parent_dirs.into(); | ||
|
||
break; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can solve this a bit differently
don't zip the two iterators but create the two iters separately and then iterate over the path
and continue as long as base and path components match, once they diverge collect the remaining into a PathBuf
this way we don't need the vecdeque
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm not sure I understand your suggestion.
If we compare the components of base and path at the same positions, it seems similar to using zip.
Could you please elaborate on the type of implementation you have in mind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
something like
let mut components = Vec::new(); // perhaps we can even directly push components to a PathBuf?
let mut base_iter = base.components();
let mut path_iter = path.components();
while let Some(path) = path_iter.next() {
if Some(path) != base_iter.next() {
components.push(path);
components.extend(path_iter);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your explanation. I now understand your point. I've made the change and pushed it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
last pedantic doc nit
src/lib.rs
Outdated
// The returned path from this function usually starts either with a normal component (e.g., `src`) | ||
// or a parent directory component (i.e., `..`), which is based on the base directory. Additionally, | ||
// this function converts the path into a UTF-8 string and replaces all separators with forward | ||
// slashes (`/`). | ||
// | ||
// The rebasing process is as follows: | ||
// | ||
// 1. Remove the leading components from the path that match the base components. | ||
// 2. Prepend `..` components to the path, equal in number to the remaining base components. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add an example here that illustrates this, otherwise this is a bit hard to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the comment, adding examples to make it easier to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
awesome job!
I'll merge both and upstream to foundry after a new release
Amazing work. Doesn't this PR also address issue foundry-rs/foundry#3507? |
@PaulRBerg I haven't looked into it deeply, but it seems like a different matter from this PR and #35, as they don't involve |
Currently, Foundry projects containing Solidity files outside the project root directory face contract verification failures on block explorers. This issue occurs from the Standard JSON including unusable source paths for external files, represented as full absolute paths in their host file systems.
This PR addresses the issue by improving the path conversion process. For files not located under the project root directory, relative parent directory paths (
..
) are used, enabling the compiler to find the files within the json.Steps to reproduce the issue are detailed in the linked issue above. Additionally, a test case representing that scenario has been added.
With this change, the json created in the reproduction scenario will appear as follows:
The source path is now aligned with the project root.
I have successfully deployed and verified the contract on Etherscan using this change.
forge create --rpc-url "wss://ethereum-holesky.publicnode.com" --verify --verifier-url "https://api-holesky.etherscan.io/api" --etherscan-api-key "..." --private-key "..." src/Counter.sol:Counter
https://holesky.etherscan.io/address/0xe08c332706185521fc8bc2b224f67adf814b1880#code