-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
feat(forge): add forge selectors collision
cmd
#5116
Conversation
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 👍
cli/src/cmd/forge/selectors.rs
Outdated
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
--check
flag 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:
|
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
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
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 selectors
to check for methods with colliding selectors between two contracts.The output format is similar to that of
forge inspect <contract> mi
but 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 Proxy
prints:and running
forge selectors collision Proxy Counter
prints: