Skip to content

script refactoring#7247

Merged
klkvr merged 34 commits into
foundry-rs:masterfrom
klkvr:klkvr/refactor-script
Mar 8, 2024
Merged

script refactoring#7247
klkvr merged 34 commits into
foundry-rs:masterfrom
klkvr:klkvr/refactor-script

Conversation

@klkvr

@klkvr klkvr commented Feb 27, 2024

Copy link
Copy Markdown
Member

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

@mattsse mattsse left a comment

Copy link
Copy Markdown
Member

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

klkvr commented Mar 4, 2024

Copy link
Copy Markdown
Member Author

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

klkvr commented Mar 4, 2024

Copy link
Copy Markdown
Member Author

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

klkvr commented Mar 4, 2024

Copy link
Copy Markdown
Member Author

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

@mattsse mattsse left a comment

Copy link
Copy Markdown
Member

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 thread crates/forge/bin/cmd/script/cmd.rs Outdated
Comment on lines 29 to 40
let pre_simulation = self
.preprocess()
.await?
.compile()?
.link()?
.prepare_execution()
.await?
.execute()
.await?
.prepare_simulation()
.await?;

Copy link
Copy Markdown
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
Copy Markdown
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

@mattsse mattsse left a comment

Copy link
Copy Markdown
Member

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

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

Copy link
Copy Markdown
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

gakonst commented Mar 5, 2024

Copy link
Copy Markdown
Member

@joshieDo cc FYI in case interested!

@DaniPopes DaniPopes left a comment

Copy link
Copy Markdown
Member

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?

Comment thread crates/forge/bin/cmd/script/sequence.rs Outdated
}
}

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

Copy link
Copy Markdown
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
Copy Markdown
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

mattsse commented Mar 6, 2024

Copy link
Copy Markdown
Member

Can we extract this into a separate crate?

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

@klkvr

klkvr commented Mar 6, 2024

Copy link
Copy Markdown
Member Author

@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

klkvr commented Mar 6, 2024

Copy link
Copy Markdown
Member Author

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 klkvr force-pushed the klkvr/refactor-script branch from 79213c3 to 300a181 Compare March 6, 2024 22:38
@klkvr

klkvr commented Mar 6, 2024

Copy link
Copy Markdown
Member Author

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

@mattsse mattsse left a comment

Copy link
Copy Markdown
Member

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

Comment thread Cargo.toml
Comment thread crates/script/src/build.rs Outdated
Comment thread crates/script/src/cmd.rs Outdated
Comment thread crates/script/src/execute.rs

@mattsse mattsse left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

pending @DaniPopes

Comment thread crates/script/src/sequence.rs Outdated
Comment thread crates/script/src/sequence.rs Outdated
Comment thread crates/script/src/multi_sequence.rs Outdated
Comment thread crates/script/src/broadcast.rs Outdated
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