-
Notifications
You must be signed in to change notification settings - Fork 2.3k
feat(forge): add forge selectors collision cmd
#5116
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
feat(forge): add forge selectors collision cmd
#5116
Conversation
Evalir
left a comment
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.
This overall looks good! Just a few comments, mainly bikeshedding on the way we handle the output:
cli/src/cmd/forge/selectors.rs
Outdated
| let second_method_map = second_artifact.method_identifiers.as_ref().unwrap(); | ||
|
|
||
| let mut colliding_methods = Vec::new(); | ||
| for (k1, v1) in first_method_map { |
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.
this is ok, but maybe we could do this in a more rusty/functional way? something like filtering whichever method map for items contained in the second and collecting this into another vector.
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.
sounds good! will rewrite this with a functional construct 👍
| colliding_methods.iter().for_each(|t| { | ||
| println!("\"{}\": {:?}", first_method_map.get(t.0).unwrap(), t) | ||
| }); | ||
| return Err(eyre::eyre!("At least one collision was found")) | ||
| } |
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.
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 a common use of this command is to run it in CI to make sure you don't merge anything with selector collisions, so my suggestion would be to either:
- Have this command always exit with an error (i.e.
std::process::exit(1)) if a collision is found, OR - Only exit with an error if a
--checkflag is added
Currently we do both depending on the command,e.g. forge build --sizes exits with an error if anything is over the size limit, but forge fmt needs a --check flag. I can see an argument that the former should also have a --check flag, so I'm indifferent here and maybe we start requiring the --check flag as a standard for commands like this where it makes sense?
Also, I'm now realizing this may all be tangential to returning an Err from this function 😅
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'm more lenient towards adding the --check flag so that we can support both of your guys' visions.
Regarding the pretty print on a table, yesterday I was looking at prettytable-rs but idk what you guys think about adding it as a dep.
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.
Other parts of the code use comfy-table to pretty-print stuff, that's what forge build --sizes uses, I think forge inspect too
|
|
||
| /// Support build args | ||
| #[clap(flatten)] | ||
| build: Box<CoreBuildArgs>, |
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.
is this box necessary?
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.
Rust won't complain without it, but clippy does as without the two elements of the SelectorsSubcommands enum differ quite a bit in size
|
@Evalir I refactored the This is what the table looks like when a collision is found: |
Evalir
left a comment
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.
this lgtm pending the comment! honestly if we find collisions i would just not return the Err, just print the table along with a "Collisions found" on top
cli/src/cmd/forge/selectors.rs
Outdated
| }); | ||
| println!("{table}"); | ||
|
|
||
| return Err(eyre::eyre!("At least one collision was found")) |
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.
Ok so what I'd do for this command is just not return an error at all—printing the table if we find collisions preceded by x collisions found is good enough for me. I'd only return an error if the command failed internally, as in building the project or trying to extract the selectors
Evalir
left a comment
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.
aight! just pushed the last change—looks good! cc @mattsse for final approval/merge
mattsse
left a comment
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.
nice job
lgtm
Motivation
Follow up PR for #5012.
Solution
Adds a subcommand to
forge selectorsto check for methods with colliding selectors between two contracts.The output format is similar to that of
forge inspect <contract> mibut it could still be improved if you guys dislike the current format.To test this I've created a forge repo in the project, added Proxy.sol and Token.sol : gist.
Running
forge selectors collision Token Proxyprints:and running
forge selectors collision Proxy Counterprints: