-
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, cast): add cast --with_local_artifacts
/forge selectors cache
to trace with local artifacts
#7359
base: master
Are you sure you want to change the base?
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.
supportive, though we can solve this a bit differently
lmk if anything's unclear
crates/cast/bin/cmd/run.rs
Outdated
|
||
#[arg(long, short, alias = "gs")] | ||
pub generate_local_signatures: bool, |
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 needs docs+explainer
crates/cast/bin/cmd/run.rs
Outdated
let _ = fs::write_json_file(&path, &cached_signatures); | ||
} | ||
} | ||
|
||
handle_traces(result, &config, chain, self.label, self.debug).await?; |
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.
perhaps a better solution than doing the preprocess step would be to provide the local signatures here:
so they can be merged with this here
foundry/crates/cli/src/utils/cmd.rs
Lines 393 to 396 in eef87de
.with_signature_identifier(SignaturesIdentifier::new( | |
Config::foundry_cache_dir(), | |
config.offline, | |
)?) |
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 implemented it in run.rs to make it optional, and handle_traces as a public method I wanted to change it as little as possible until I understood all others crates package if refered to 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.
In fact, it makes more sense for this function to be executed at forge compile time, and it apears in cast run as a shortcut entry to avoid typing the command twice.
crates/cast/bin/cmd/run.rs
Outdated
use std::collections::BTreeMap; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Default, Serialize, Deserialize)] | ||
struct CachedSignatures { | ||
events: BTreeMap<String, String>, | ||
functions: BTreeMap<String, String>, | ||
} |
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.
we already have this type here
foundry/crates/evm/traces/src/identifier/signatures.rs
Lines 14 to 18 in edb3a4b
#[derive(Debug, Default, Serialize, Deserialize)] | |
struct CachedSignatures { | |
events: BTreeMap<String, String>, | |
functions: BTreeMap<String, String>, | |
} |
we should prevent duplicating this and instead find a way to reuse the existing type
we can make the type pub instead and also make this a helper function:
foundry/crates/evm/traces/src/identifier/signatures.rs
Lines 44 to 56 in eef87de
let identifier = if let Some(cache_path) = cache_path { | |
let path = cache_path.join("signatures"); | |
trace!(target: "evm::traces", ?path, "reading signature cache"); | |
let cached = if path.is_file() { | |
fs::read_json_file(&path) | |
.map_err(|err| warn!(target: "evm::traces", ?path, ?err, "failed to read cache file")) | |
.unwrap_or_default() | |
} else { | |
if let Err(err) = std::fs::create_dir_all(cache_path) { | |
warn!(target: "evm::traces", "could not create signatures cache dir: {:?}", err); | |
} | |
CachedSignatures::default() | |
}; |
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 defined it again because I find it does not exported. For maintenance reasons, I think you're right. At first I was just using it for myself so I didn't think about it that much, I'll spend some time refactoring the code next.
2a08d1c
to
4f0ee53
Compare
I updated my code. please check again @mattsse |
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.
sorry this one slipped through,
some nits.
generally supportive, wdyt @DaniPopes @klkvr
crates/cli/src/utils/cmd.rs
Outdated
@@ -414,3 +414,25 @@ pub async fn print_traces(result: &mut TraceResult, decoder: &CallTraceDecoder) | |||
println!("Gas used: {}", result.gas_used); | |||
Ok(()) | |||
} | |||
|
|||
pub fn generate_local_signatures(output: &ProjectCompileOutput, cache_path: PathBuf) -> Result<()> { |
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 needs docs and should be renamed to cache_local_signatures
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 i'll fix it later
crates/cast/bin/cmd/run.rs
Outdated
@@ -220,6 +227,19 @@ impl RunArgs { | |||
} | |||
}; | |||
|
|||
if self.generate_local_signatures { | |||
let project = config.project()?; |
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 should print that we're compiling to get the signatures
crates/cast/bin/cmd/run.rs
Outdated
@@ -220,6 +227,19 @@ impl RunArgs { | |||
} | |||
}; | |||
|
|||
if self.generate_local_signatures { | |||
let project = config.project()?; | |||
let compiler = ProjectCompiler::new().quiet(true); |
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.
we don't need to actually compile here, right?
@klkvr is there an easier way to just get the artifacts?
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.
we need to compile as it might be run on a clean project. though I think we can only request abi here, should speed things up
if there are cached artifacts then compilation would just use them, so that's fine I believe
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.
Usually users are more likely to trace their own project files and compile the whole project before deploying. But some one may dont want to run two command to generate signature cache with new file updates (may be an upgradable contract should try different events). If file not updated, compile will be complete fast.
crates/cli/src/utils/cmd.rs
Outdated
@@ -414,3 +414,25 @@ pub async fn print_traces(result: &mut TraceResult, decoder: &CallTraceDecoder) | |||
println!("Gas used: {}", result.gas_used); | |||
Ok(()) | |||
} | |||
|
|||
pub fn generate_local_signatures(output: &ProjectCompileOutput, cache_path: PathBuf) -> Result<()> { | |||
let mut cached_signatures = CachedSignatures::default(); |
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.
shouldn't we firstly read the contents of the file here? looks like this always overwrites existing cache
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 believe that generating function signatures for a single project.sol file during most project debugging is sufficient, so I choose to overwrite the existing file. If you want to merge the original signature cache, you also need to consider the handling logic for 4-byte signature conflicts. Such as same 4-byte signature with different arguments
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 don't think it's correct to override existing cache anyway. That way running cast run ... --generate-local-signatures
twice would result in a bunch of duplicated requests to fetch signatures for unknown contracts
Also wondering if we should instead inject local abis into CallTraceDecoder
directly? This would allow us to also decode output values. SignatureIdentifier
is mostly suited for decoding only selectors of external contracts
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.
@klkvr Thank you for your guidance. While implementing this feature, I was focused on getting it ready for trace call as soon as possible and didn't look closely at the SignatureIdentifier
part. I think I need some time to finish modifying the code, test it with examples of 4-byte signature conflicts, and then resubmit.
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 kept the cached local signatures and merged the new signatures with them. However, I need to point out the issue you mentioned earlier with the SignatureIdentifier
. If a function's 4-byte signature matches one in the local signatures, the SignatureIdentifier
will not automatically attempt to fetch a matching function from external sources, even if the parameters do not match.
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.
signature-test.zip
pic1:
pic2:
with test sol files, deploy and call run, then cast run
trace will output like the pic1.
vm.startBroadcast(pkey);
Foobar foo1 = new Foobar();
Foobar2 foo2 = new Foobar2();
Foobar3 foo3 = new Foobar3(foo1, foo2);
foo3.run();
vm.stopBroadcast();
and then I remove "0x6a627842":"watch_tg_invmru_89cb189(uint256,address)"
in the cache file, then cast run
trace will output like the pic2. anyway that is an another question.
how to proceed here @klkvr ? |
crates/cli/src/utils/cmd.rs
Outdated
| NamedChain::ArbitrumTestnet | ||
| NamedChain::ArbitrumGoerli | ||
| NamedChain::ArbitrumSepolia | ||
| NamedChain::Moonbeam |
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.
please remove all the formatting changes
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.
sorry for my mistakes, I will fix it
crates/cli/src/utils/cmd.rs
Outdated
let cache_contents = std::fs::read_to_string(path.clone()).unwrap(); | ||
match serde_json::from_str::<CachedSignatures>(&cache_contents) { | ||
Ok(existed_signatures) => cached_signatures = existed_signatures, | ||
Err(e) => { | ||
println!("parse cached local signatures file error: {}", e); | ||
} | ||
} | ||
dbg!(&cached_signatures); |
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 now duplicated with SignatureIdentifier::new
, can we move this logic to CachedSignatures::load(path)
So this can be broken into 2 separate usecases
|
825579e
to
c575b2d
Compare
…racts functions and events
merge project signatures with exists cached local signatures instead of just override them
For case 1, I believe having helper options in For case 2, I have considered the solution you mentioned. However, the changes involved are quite extensive and a bit difficult for me, which is why I chose the current method. It allows me to get it working quickly. |
thanks @byteshijinn ! I made following changes and updated the PR:
Adding tests is a little bit hard, how I tested locally was to:
@klkvr mind to review? thank you! |
cast --with_local_artifacts
/forge selectors cache
to trace with local artifacts
Motivation
Closes #8949
Closes #8581
Supply a fast way to add all project contracts functions and events to signatures makes them decode correctly.
Solution
This PR introduces such a possibility using a cli argument --generate-local-signatures for cast run.