Skip to content
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

script refactoring #7247

Merged
merged 34 commits into from
Mar 8, 2024
Merged

script refactoring #7247

merged 34 commits into from
Mar 8, 2024

Conversation

klkvr
Copy link
Member

@klkvr klkvr commented Feb 27, 2024

Motivation

The idea is to refactor script to be more like a state-machine, so its easier to navigate/update and we are able to debug each state transition separately.

Solution

I've started with build module, it now returns and operates on BuildData and LinkedBuildData structs which contain all build artifacts and solc-related data and allow us to use them through script execution instead of passing Linker everywhere.

Closes #7244
Closes #4476

@klkvr klkvr marked this pull request as draft February 27, 2024 18:01
Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this approach a lot.

structuring this in compile+link steps makes a lot of sense

@klkvr
Copy link
Member Author

klkvr commented Mar 4, 2024

Refactoring goals were mostly increasing readability and safety of the code.

Readability right now should be better because the logic overall became more flat. If earlier we had handle_broadcastable_transactions going up to 4-5 functions deep, it's now split across several states which are invoked sequentially and don't go deeper than 2 small functions.

Safety isn't great because we have a lot of Options which are assumed to be Some after some point. It is not really easy to know where this point is and it does not help both reading existing code and extending it. I've tried to reduce such practicies as well. Example of those is ScriptConfig:

pub target_contract: Option<ArtifactId>,
/// Function called by the script
pub called_function: Option<Function>,
/// Unique list of rpc urls present
pub total_rpcs: HashSet<RpcUrl>,
/// If true, one of the transactions did not have a rpc
pub missing_rpc: bool,

All of those parameters are initialized with default values and populated later, accessing those in the wrong place might result in panic or unintended behavior.

I've also simplified logic where it was possible, however, we still have several pretty long functions which would be nice in the shorter form, but this can be fixed a bit later, esp considering that all of the state transaction functions are normally readable

@klkvr
Copy link
Member Author

klkvr commented Mar 4, 2024

And we also no more need the --multi flag, because we are executing script anyway and have the full list of RPCs before resuming, so we can just check if it has more than 1 RPC: https://github.com/klkvr/foundry/blob/klkvr/refactor-script/crates/forge/bin/cmd/script/resume.rs#L31

@klkvr
Copy link
Member Author

klkvr commented Mar 4, 2024

We should also be able to remove onchain simulation step once we have isolation mode enabled by default

Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks great, this is a lot easier to navigate

I'd like to see a few more docs on functions,types,fields

Comment on lines 29 to 40
let pre_simulation = self
.preprocess()
.await?
.compile()?
.link()?
.prepare_execution()
.await?
.execute()
.await?
.prepare_simulation()
.await?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is great!

I'd like a few more function docs that cover the workflow

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still would like a brief explainer for run_script, what the individual steps are

@klkvr klkvr marked this pull request as ready for review March 4, 2024 20:01
@klkvr klkvr requested a review from mattsse March 4, 2024 20:01
@klkvr klkvr changed the title [wip] script refactoring script refactoring Mar 4, 2024
Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the individual states are very easy to follow now.

@DaniPopes would appreciate a closer look

crates/forge/bin/cmd/script/execute.rs Outdated Show resolved Hide resolved
crates/forge/bin/cmd/script/resume.rs Outdated Show resolved Hide resolved
Comment on lines 29 to 40
let pre_simulation = self
.preprocess()
.await?
.compile()?
.link()?
.prepare_execution()
.await?
.execute()
.await?
.prepare_simulation()
.await?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still would like a brief explainer for run_script, what the individual steps are

@gakonst
Copy link
Member

gakonst commented Mar 5, 2024

@joshieDo cc FYI in case interested!

Copy link
Member

@DaniPopes DaniPopes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extract this into a separate crate?

}
}

pub fn iter_sequences(&self) -> impl Iterator<Item = &ScriptSequence> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fn sequences{_mut}(&self) -> &[ScriptSequence] rather than iter IMO

use alloy_json_abi::{Function, InternalType, JsonAbi};
use alloy_primitives::{Address, Bytes, Log, U256, U64};
use alloy_rpc_types::request::TransactionRequest;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no spaces in between imports

@mattsse
Copy link
Member

mattsse commented Mar 6, 2024

Can we extract this into a separate crate?

oh yeah, totally forgot about this, I'd like that, yes

@klkvr
Copy link
Member Author

klkvr commented Mar 6, 2024

@DaniPopes @mattsse I fthink it makes sense to avoid having clap dependency in the separate crate. A reasonable way to do this might be to move some of ScriptArgs methods to ScriptConfig and populate them in ScriptArgs::preprocess. But we'd duplicate half of ScriptArgs fields that way.

Do you see any cleaner solution here?

@klkvr
Copy link
Member Author

klkvr commented Mar 6, 2024

ah, we'd still need clap for VerifyArgs, so we can either line up verification extraction and get rid of clap where it will be possible then, or divide ScriptArgs and ScriptConfig now anyway

@klkvr
Copy link
Member Author

klkvr commented Mar 6, 2024

Extracted scripting code to separate crate and also removed ScriptArgs dependency on BuildArgs. It now uses CoreBuildArgs + separate --skip parameter. Removed params are --names, --sizes, --watch* and --format-json. All of those had not effect. This change should close #4476

Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

amazing.

I see that a few impl blocks are not colocated with thir struct def, this is probably because the previous ScriptArgs impl was scattered across multiple files, but this makes it a lot harder to navigate.

impl blocks should go under their respective struct def

Cargo.toml Show resolved Hide resolved
crates/script/src/build.rs Outdated Show resolved Hide resolved
crates/script/src/cmd.rs Outdated Show resolved Hide resolved
crates/script/src/execute.rs Show resolved Hide resolved
Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

pending @DaniPopes

crates/script/src/sequence.rs Outdated Show resolved Hide resolved
crates/script/src/sequence.rs Outdated Show resolved Hide resolved
crates/script/src/multi_sequence.rs Outdated Show resolved Hide resolved
crates/script/src/broadcast.rs Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Misleading Error Message: Could not find target contract forge script --watch is not watching anything
4 participants