Skip to content

Modularize forge-std - #126

Merged
ZeroEkkusu merged 26 commits into
foundry-rs:v0.3from
PaulRBerg:refactor-cheats
Jul 26, 2022
Merged

Modularize forge-std#126
ZeroEkkusu merged 26 commits into
foundry-rs:v0.3from
PaulRBerg:refactor-cheats

Conversation

@PaulRBerg

@PaulRBerg PaulRBerg commented Jul 15, 2022

Copy link
Copy Markdown
Contributor

Implements #122, #123, and #124.

Modularization

  • Assertions and logs moved to Assertions.sol
  • Cheatcodes moved to Cheats.sol
  • Errors lib stdErrors moved to Errors.sol
  • Math lib stdMath moved to Math.sol
  • Utilities (such as bound) moved to Utils.sol - also moved the utilities from Script.sol to Utils.sol
  • Test now inherits from Assertions, Cheats and Utils

New Features

  • createCompute2Address utility

Fixes

  • Drop the pragma to 0.8.0 in StdErrors.t.sol

Breaking Changes

  • Removed the now-deprecated lowLevelError custom error
  • Removed the now-deprecated tip cheat
  • Test doesn't inherit from Script anymore

I'm very much open to any feedback. Feel free to destroy this.

@PaulRBerg
PaulRBerg force-pushed the refactor-cheats branch 2 times, most recently from 891cc2b to 5ba6127 Compare July 15, 2022 11:29
@mds1

mds1 commented Jul 15, 2022

Copy link
Copy Markdown
Collaborator

In general some cleanup and modularity seems good to me. I haven't looked closely at this yet, but just commenting to say that if we're going to a big refactor like this there's some other things we should consider including. Namely, splitting Vm into something like VmSafe and Vm is VmSafe, where VmSafe is a subset that's safe to use on scripts intended for a live network, so you don't accidentally e.g. change the block timestamp and use a fake timestamp as a value somewhere. You can also imagine a version where all cheatcodes like vm.roll are replaced with roll which are aliases for anvil RPC calls, to help scaffold local nodes for e.g. frontend dev/testing.

I wrote up some of this this in #78, I'll need to review that to see if I still agree with it 😅

As a side note, thanks for all the recent issues/PRs to forge-std! 🙌

@PaulRBerg

Copy link
Copy Markdown
Contributor Author

if we're going to a big refactor like this there's some other things we should consider including.

Yep, happy to move this to another bigger PR if appropriate.

Alternatively, happy to split this PR into its constituent components so reviewing each proposal is easier.

splitting Vm into something like VmSafe and Vm is VmSafe, where VmSafe is a subset that's safe to use on scripts intended for a live network

That would be cool!

As a side note, thanks for all the recent issues/PRs to forge-std! 🙌

Very glad that I can help.

@brockelmore

Copy link
Copy Markdown
Contributor

fwiw this is how it used to be structured, but from a dev UX standpoint, it seemed monolithic was generally better. I am sympathetic to wanting to modularize, and as long as basically all normal users can still import a single test contract and it be clean (single inherit, no MyLib.funcCall, etc), I am okay with it.

cc @gakonst

@PaulRBerg

Copy link
Copy Markdown
Contributor Author

it seemed monolithic was generally better

My proposal would still be "monolithic" for the end user - it's just that we internally would maintain the Cheats as a separate entity. The primary advantage (as I said in #122) would be to make Forge Std more modular and composable with other testing frameworks than DSTest.

single inherit, no MyLib.funcCall

Yeah that wouldn't be cool.

@ZeroEkkusu ZeroEkkusu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm very supportive of making Forge Std modular to allow for maximal interoperability. It'd be great to standardize more things about testing in Solidity / frameworks, but that's out of scope of this PR, of course.

I just took a look at the changes and have a few questions.

One suggestion I have is to modularize every part of Forge Std (Std Errors, etc) and then just import them in Test.

Notes:

  • We should make a new release before implementing these changes
  • The tip std-cheat, which was deprecated, is removed

+1 for keeping naming simple with Cheats, Storage, etc!

Comment thread src/Cheats.sol Outdated
Comment thread src/Script.sol
Comment thread src/Storage.sol Outdated
Comment thread src/Storage.sol Outdated
Comment thread src/Test.sol
Comment thread src/Test.sol Outdated
Comment thread src/Cheats.sol Outdated
using stdStorage for StdStorage;

StdStorage private stdstore;
Vm private constant vm_cheats = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));

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 should be inherited

Suggested change
Vm private constant vm_cheats = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
Vm internal constant vm_cheats = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You mean inherited in Test?

The problem with marking it as internal is that there would be collisions with the third-party testing frameworks which need to also define vm such that that framework can used independently of forge-std (for example, I define vm in PRBTest).

I suggest leaving it as private. Forge Std already redeclares the vm in Test.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think a good approach to enabling composability long-term may be for individual components (Cheats, etc) to provide only the functionality they are made for.
E.g. Cheats should expose std-cheats; not vm because it's a Forge thing and not a feature of Cheats. This will also prevent collisions when composing, and some devs might come up with interesting combinations we cannot foresee.

Additionally, every component should be a self-contained unit, with its own private vm and stdstore if it needs it, so it does not depend on another component. I don't think that would be too much hassle.

Specifically made end-user contracts, such as Test and Script can expose vm and stdstore.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Very much agree with @ZeroEkkusu's resolution here.

every component should be a self-contained unit, with its own private vm and stdstore

+1

@PaulRBerg

Copy link
Copy Markdown
Contributor Author

Hi @ZeroEkkusu, thanks very much for your review.

One suggestion I have is to modularize every part of Forge Std (Std Errors, etc) and then just import them in Test.

I'll work on this and push another commit to this PR.

We should make a new release before implementing these changes

yep! v0.2.0 I guess?

The tip std-cheat, which was deprecated, is removed

Yeah well I have thought that since this introduces breaking changes anyway, we may just be able to delete the tip function.

@PaulRBerg

Copy link
Copy Markdown
Contributor Author

@ZeroEkkusu I have addressed all of your comments. Also, in my recent commit, I have created two new files Errors.sol and Math.sol to modularize stdErrors and stdMath. Let me know if that looks good to you!

@ZeroEkkusu ZeroEkkusu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I left a couple of suggestions.

[Modularize] I'll work on this and push another commit to this PR.

Should we move out the assertions, as well?
The logs can stay inside Test because they are specific to Foundry, no need for a header.

As for bound, I thought we could add it and the utils from Script to Utils.sol, but haven't thought about this much.

Comment thread src/Errors.sol
Comment thread src/Errors.sol Outdated
Comment thread src/Math.sol Outdated
Comment thread src/Test.sol Outdated
@PaulRBerg

Copy link
Copy Markdown
Contributor Author

Should we move out the assertions, as well?

Just did it!

The logs can stay inside Test because they are specific to Foundry, no need for a header.

Actually, no. I had to move the logs to the newly created Assertions file because the assertions depended upon some logs, e.g. log_array.

As for bound, I thought we could add it and the utils from Script to Utils.sol, but haven't thought about this much.

Hah, this was my 2nd proposal from #123.

I just did this in the last commit. The only cost was the inability to use log_named_uint in bound anymore - though this should be fine? I don't see why users would want Forge Std to log the bounded value.

@PaulRBerg PaulRBerg mentioned this pull request Jul 18, 2022

@ZeroEkkusu ZeroEkkusu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I had to move the logs to the newly created Assertions file because the assertions depended upon some logs, e.g. log_array.

Right, I forgot about this!

Here's an idea for logging the bound result:

Comment thread src/Utils.sol Outdated
@PaulRBerg

Copy link
Copy Markdown
Contributor Author

Okay, this is starting to look good! @ZeroEkkusu, I have made the following final touches:

  1. Fix the compiler warning in bound - Solidity complained that the return value from the staticcall wasn't used.
  2. Re-add vm to Script to fix the mistake you spotted in one of the comments above.
  3. Define console2's address as a constant in Utils.sol, for better readability.

I will work on fixing the git conflicts tomorrow if this also LGT everyone else?

@ZeroEkkusu ZeroEkkusu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It is starting to lg. Thank you for all the effort and patience.

I will work on fixing the git conflicts

I checked today, the conflicts are minimal.

Comment thread src/Utils.sol Outdated
@ZeroEkkusu
ZeroEkkusu requested a review from brockelmore July 18, 2022 22:39
Comment thread src/Utils.sol Outdated
Comment thread src/Cheats.sol
Comment thread src/Script.sol Outdated
Comment thread src/Test.sol Outdated
Comment thread src/Utils.sol
@PaulRBerg

Copy link
Copy Markdown
Contributor Author

Hey @mds1, thanks for your review.

There's lot of related issues, where's the best place to get an explanation of the new architecture and UX being implemented in this PR?

@ZeroEkkusu and I have worked our way up to modularize the code base commit by commit .. besides the original proposals that I made in #122, #123, and #124, there's no central place where all changes are documented. What I will do now though is write a brief spec in my PR comment body at the top - let me know what you think.

PaulRBerg and others added 6 commits July 19, 2022 11:05
refactor: new category StdUtils
refactor: unbundle Test from Script
Mark "vm_cheats" as "private"
Instantiate a "vm" in "Test.sol"
refactor: rename "vm_cheats" to just "vm"
refactor: rename "vm_std_store" to just "vm"
refactor: delete "INT256_MAX" and "UINT256_MAX"
revert: redeclare "stdstore" in "Test"
refactor: move "stdMath" to "Math.sol"
Co-authored-by: Zero Ekkusu <94782988+ZeroEkkusu@users.noreply.github.com>
chore: delete stale "using stdStorage for StdStorage"
@mds1 mds1 mentioned this pull request Jul 22, 2022

@ZeroEkkusu ZeroEkkusu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Team, this is the recap of the PR:

  • No breaking changes besides the ones we've made deliberately
  • The library is now modular
  • One gotcha: DSTest is not flexible and we could not separate IS_TEST from the assertions; we inherited DSTest in both Test and Assertions

Lgtm.
@mds1, we should consider merging into v0.3.

I will open an issue to track proposals for v0.3.

@ZeroEkkusu
ZeroEkkusu requested a review from mds1 July 24, 2022 18:34
@PaulRBerg

Copy link
Copy Markdown
Contributor Author

Thanks very much @ZeroEkkusu for your continuous guidance on this PR!

No breaking changes besides the ones we've made deliberately

In case you're looking for a list of breaking changes, see my top comment.

@gakonst gakonst 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.

Went through the code and the refactor LGTM. Trust you guys above that the user testing makes sense and that there's no critical breaking changes. Would be helpful to document if any.

@ZeroEkkusu

Copy link
Copy Markdown
Contributor

Alright, we're merging this into v0.3! Thank you @PaulRBerg for taking the initiative and bearing with us!

If Matt finds something is missing, we can make changes in v0.3.

@PaulRBerg

Copy link
Copy Markdown
Contributor Author

Whoop whoop!

I went ahead and closed issues #122, #123 and #124.

@PaulRBerg
PaulRBerg deleted the refactor-cheats branch July 26, 2022 20:23
@ZeroEkkusu ZeroEkkusu mentioned this pull request Sep 21, 2022
2 tasks
mds1 added a commit that referenced this pull request Oct 31, 2022
* Modularize forge-std (#126)

* refactor: unbundle cheats from assertions

refactor: new category StdUtils
refactor: unbundle Test from Script

* Rename "vm" to "vm_cheats" in "Cheats.sol"

Mark "vm_cheats" as "private"
Instantiate a "vm" in "Test.sol"

* refactor: remove deprecated "lowLevelError"

refactor: rename "vm_cheats" to just "vm"
refactor: rename "vm_std_store" to just "vm"
refactor: delete "INT256_MAX" and "UINT256_MAX"
revert: redeclare "stdstore" in "Test"

* refactor: move "stdErrors" to "Errors.sol"

refactor: move "stdMath" to "Math.sol"

* Add note about versions in "Errors.sol|

Co-authored-by: Zero Ekkusu <94782988+ZeroEkkusu@users.noreply.github.com>

* chore: delete stale delineators in Errors and Math

chore: delete stale "using stdStorage for StdStorage"

* refactor: modularize assertions and utils

docs: add NatSpec tag @dev in "console2"
refactor: delete log from "bound" function
refactor: move "addressFromLast20Bytes" to "Utils.sol"
refactor: move "bound" to "Utils.sol"
refactor: move "computeCreateAddress" to "Utils.sol"
style: move brackets on same line with "if" and "else" in "bound"

* Log bound result with static call to `console.log`

Co-authored-by: Zero Ekkusu <94782988+ZeroEkkusu@users.noreply.github.com>

* fix: reintroduce "vm" in "Script.sol"

chore: silence compiler warning in "bound"
refactor: define console2.log address as constant in "Utils.sol"

* test: move "testGenerateCorrectAddress" to "StdUtils.t.sol"

* Nit: remove unnecessary "bytes20" casts

* style: add white-spaces in "deal"

* fix: readd "deployCode" functions with "val"

* Add "computeCreate2Address" utility

Rename "testGenerateCorrectAddress" to "testGenerateCreateAddress"

* refactor: use "console2" in "Utils.sol"

* style: end lines and white spaces

* test: drop pragma to ">=0.8.0" in "StdError.t.sol"

chore: remove comment about "v0.8.10" in "Errors.sol"

* refactor: define "vm" and "stdStorage" in "TestBase"

feat: add "Components.sol" file which re-exports everything

* fix: inherit from DSTest in Test

* feat: ScriptBase

refactor: delete "TestBase.sol"
refactor: move TestBase in "Test.sol"

* ♻️ Make assertions virtual

* ♻️ Make deployCode virtual

* ✨ (Components) Export consoles

* ♻️ (Script) Import Vm

* ♻️ Import from Components

* ♻️ Make bound view

Co-authored-by: Zero Ekkusu <94782988+ZeroEkkusu@users.noreply.github.com>

* feat: make `Script` safer (#147)

* feat: add `stdStorageSafe`

* test(cheats): fix tests
`deployCode` tests started failing after 01c60f9

* refactor: make components `abstract`

* feat: add `CheatsSafe`

* feat: add `VmSafe`

* refactor: update `Script`

* docs: add license info (#156)

* feat: rebrand components (#157)

* feat: rebrand components
Rename to Std<Component>

* fix: StdErrors -> StdError

* chore: remove `.DS_Store`

* fix: use `ABIEncoderV2`

* test: correct test name

* fix: add `CommonBase`

* refactor: move test dir to root

* Revert "refactor: move test dir to root"

This reverts commit f21ef1a.

* refactor: move test dir to root, update ci accordingly

* style: configure and run forge fmt

* ci: split into jobs and add fmt job

* ci: update name and triggers

* ci: remove name field

* feat: better bound, ref #188

* fix: bound logs + remove unneeded line

* fix: update require strings

* refactor: clean up `Test` and `Script`
- do not forge fmt Components import
- do not import Safe Components in `Test`

* fix: udpate bound to match forge's uint edge bias strategy

* feat: add interfaces (#193)

* chore: update function visibility

* feat: add interfaces

* fix: fix import

* style: consistent spec style

* chore: fix find/replace issue

Co-authored-by: Zero Ekkusu <94782988+ZeroEkkusu@users.noreply.github.com>

* chore: update comments

Co-authored-by: Zero Ekkusu <94782988+ZeroEkkusu@users.noreply.github.com>

Co-authored-by: Zero Ekkusu <94782988+ZeroEkkusu@users.noreply.github.com>

* feat: reimplement `bound` w/ even distribution

* build: rename step

* Add memory-safe notation so that compiling via-ir can optimize effectively (#196)

* test(bound): add even distribution test (#197)

* feat: add `assumeNoPrecompiles` (#195)

* refactor: use fully-qualified paths instead of relative paths

* chore: fix typo

* feat: start adding StdChains

* feat: start adding assumeNoPrecompiles

* feat: add chains

* feat: add precompiles/predeploys

* Revert "refactor: use fully-qualified paths instead of relative paths"

This reverts commit bb2579e.

* refactor: use relative paths for compatibility with solc <0.6.9 (no --base-path flag)

* refactor: make assumeNoPrecompiles virtual

* refactor: no more constructor warning from StdChains

* fix: move stdChains into StdCheats, fix constructor initalization order, move cheats into VmSafe that can be safely used

* ♻️ update ds-test (#200)

* ♻️ update ds-test

Signed-off-by: Pascal Marco Caversaccio <pascal.caversaccio@hotmail.ch>

* ♻️  use relative path for ds-test imports

Signed-off-by: Pascal Marco Caversaccio <pascal.caversaccio@hotmail.ch>

Signed-off-by: Pascal Marco Caversaccio <pascal.caversaccio@hotmail.ch>

* refactor: move `UINT256_MAX` to `CommonBase`

Signed-off-by: Pascal Marco Caversaccio <pascal.caversaccio@hotmail.ch>
Co-authored-by: Paul Razvan Berg <hello@paulrberg.com>
Co-authored-by: Matt Solomon <matt@mattsolomon.dev>
Co-authored-by: Drake Evans <31104161+DrakeEvans@users.noreply.github.com>
Co-authored-by: Pascal Marco Caversaccio <pcaversaccio@users.noreply.github.com>
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.

Meta: Unbundling Test from Script Meta: New category StdUtils Meta: Unbundling the cheats from the assertions (leg 1)

5 participants