Skip to content

feat(forge): optimize compilation through preprocessing and caching #10010

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

Merged
merged 38 commits into from
Apr 7, 2025

Conversation

grandizzy
Copy link
Collaborator

@grandizzy grandizzy commented Mar 4, 2025

Motivation

TODO

Project Change Files compiled (with / without, after initial compile) Time to compile (with / without, after initial compile)
uniswap v4-core add Lock.lock(); at PoolManager.sol#L107 1 / 19 2.25s / 165.13s
spark-psm change amountOut < minAmountOut at PSM3.sol#L125 3 / 28 2.14s / 16.15s
morpho-blue-bundlers change if (assets < 0) at MorphoBundler.sol#L106 11 / 36 16.39s / 251.05s
morpho-blue add require(assets != 0, ErrorsLib.ZERO_ASSETS) at Morpho.sol#L424 1 / 23 1.01s / 133.73s
sablier lockup change if (cliffTime < 0) at SablierLockup.sol#L480 1 / 104 781ms / 71.29s
solady add additional _setOwner(newOwner) at Ownable.sol#L182 9 / 14 6.17s / 6.34s
euler evc change SET_MAX_ELEMENTS to 11 at Set.sol#L7 28 / 30 9.17s / 9.40s

Solution

PR Checklist

  • Added Tests
  • Added Documentation
  • Breaking changes

@zerosnacks
Copy link
Member

zerosnacks commented Mar 5, 2025

added morpho-blue to the benchmark, I haven't ran into any errors or unexpected results

working on adding aave-v3-origin

depending on the edited file the results are mixed in impact but always more favorable with test caching enabled

@zerosnacks
Copy link
Member

zerosnacks commented Mar 5, 2025

For aave-v3-origin it appears that there is very limited impact, unsure why it recompiles the tests like this:

Project Change Files compiled (with / without, after initial compile) Time to compile (with / without, after initial compile)
aave-v3-origin add additional _bridgeProtocolFee = protocolFee at Pool.sol#L683 80 / 84 61.38s / 62.11s
- scripts/DeployAaveV3MarketBatched.sol
- src/contracts/instances/L2PoolInstance.sol
- src/contracts/instances/PoolInstance.sol
- src/contracts/mocks/helpers/MockL2Pool.sol
- src/contracts/mocks/helpers/MockPool.sol
- src/contracts/protocol/pool/L2Pool.sol
- src/contracts/protocol/pool/Pool.sol
- src/deployments/contracts/procedures/AaveV3L2PoolProcedure.sol
- src/deployments/contracts/procedures/AaveV3PoolProcedure.sol
- src/deployments/projects/aave-v3-batched/AaveV3BatchOrchestration.sol
- src/deployments/projects/aave-v3-batched/batches/AaveV3L2PoolBatch.sol
- src/deployments/projects/aave-v3-batched/batches/AaveV3PoolBatch.sol
- tests/deployments/AaveV3BatchDeployment.t.sol
- tests/deployments/AaveV3BatchTests.t.sol
- tests/deployments/AaveV3PermissionsTest.t.sol
- tests/deployments/DeploymentsGasLimits.t.sol
- tests/extensions/paraswap-adapters/ParaswapAdapters.t.sol
- tests/extensions/stata-token/ERC20AaveLMUpgradable.t.sol
- tests/extensions/stata-token/ERC4626StataTokenUpgradeable.t.sol
- tests/extensions/stata-token/StataTokenV2Getters.sol
- tests/extensions/stata-token/StataTokenV2Pausable.t.sol
- tests/extensions/stata-token/StataTokenV2Permit.sol
- tests/extensions/stata-token/StataTokenV2Rescuable.sol
- tests/extensions/stata-token/TestBase.sol
- tests/extensions/v3-config-engine/AaveV3ConfigEngineTest.t.sol
- tests/gas/AToken.Transfer.gas.t.sol
- tests/gas/Pool.Getters.gas.t.sol
- tests/gas/Pool.Operations.gas.t.sol
- tests/gas/Pool.Setters.gas.t.sol
- tests/gas/ProtocolDataProvider.gas.t.sol
- tests/gas/StataToken.gas.t.sol
- tests/gas/Testhelpers.sol
- tests/gas/WrappedTokenGatewayV3.gas.t.sol
- tests/helpers/WrappedTokenGateway.t.sol
- tests/invariants/CryticToFoundry.t.sol
- tests/invariants/Tester.t.sol
- tests/misc/AaveOracle.t.sol
- tests/misc/PriceOracleSentinel.t.sol
- tests/misc/rates/RateStrategy.calculateRates.t.sol
- tests/misc/rates/RateStrategy.setters.t.sol
- tests/misc/rates/RateStrategy.t.sol
- tests/misc/rates/RateStrategy.template.sol
- tests/protocol/configuration/ACLManager.t.sol
- tests/protocol/configuration/AddressesProviderRegistry.t.sol
- tests/protocol/configuration/PoolAddressesProvider.t.sol
- tests/protocol/libraries/logic/BridgeLogic.t.sol
- tests/protocol/libraries/logic/PoolLogic.initReserves.edge.t.sol
- tests/protocol/pool/L2Pool.t.sol
- tests/protocol/pool/Pool.Borrow.t.sol
- tests/protocol/pool/Pool.Deficit.sol
- tests/protocol/pool/Pool.EMode.sol
- tests/protocol/pool/Pool.FlashLoans.t.sol
- tests/protocol/pool/Pool.Liquidations.CloseFactor.t.sol
- tests/protocol/pool/Pool.Liquidations.t.sol
- tests/protocol/pool/Pool.Repay.t.sol
- tests/protocol/pool/Pool.Supply.t.sol
- tests/protocol/pool/Pool.Withdraw.t.sol
- tests/protocol/pool/Pool.t.sol
- tests/protocol/pool/pool-configurator/PoolConfigurator.ACLModifiers.t.sol
- tests/protocol/pool/pool-configurator/PoolConfigurator.borrowCaps.t.sol
- tests/protocol/pool/pool-configurator/PoolConfigurator.eMode.sol
- tests/protocol/pool/pool-configurator/PoolConfigurator.initReserves.t.sol
- tests/protocol/pool/pool-configurator/PoolConfigurator.liquidationFee.t.sol
- tests/protocol/pool/pool-configurator/PoolConfigurator.pendingLTV.t.sol
- tests/protocol/pool/pool-configurator/PoolConfigurator.reserveRiskConfig.t.sol
- tests/protocol/pool/pool-configurator/PoolConfigurator.supplyCaps.t.sol
- tests/protocol/pool/pool-configurator/PoolConfigurator.upgradeabilty.t.sol
- tests/protocol/tokenization/ATokenEdgeCases.t.sol
- tests/protocol/tokenization/ATokenEvents.t.sol
- tests/protocol/tokenization/ATokenModifiers.t.sol
- tests/protocol/tokenization/ATokenPermit.t.sol
- tests/protocol/tokenization/ATokenRepay.t.sol
- tests/protocol/tokenization/ATokenRescueTokens.sol
- tests/protocol/tokenization/ATokenTransfers.t.sol
- tests/protocol/tokenization/ScaledBalanceTokenBase.t.sol
- tests/protocol/tokenization/VariableDebtToken.t.sol
- tests/rewards/EmissionsManager.t.sol
- tests/rewards/RewardsController.t.sol
- tests/rewards/StakedTokenTransferStrategy.t.sol
- tests/template/BaseTest.t.sol

The diff (with / without test caching) being limited to:

- scripts/misc/DeployAaveV3MarketBatchedBase.sol
- tests/invariants/Setup.t.sol
- tests/utils/BatchTestProcedures.sol
- tests/utils/TestnetProcedures.sol

Alternatively:

Project Change Files compiled (with / without, after initial compile) Time to compile (with / without, after initial compile)
aave-v3-origin add additional unchecked { result = result / SECONDS_PER_YEARl } at MathUtils.sol#L32 98 / 104 61.75s / 62.06s

Can also just be a side effect of how the codebase is set up with very deep hierarchies

@grandizzy
Copy link
Collaborator Author

Can also just be a side effect of how the codebase is set up with very deep hierarchies

Yeah, most probably many mocks aka contracts under test that extend contracts under src, like for example

contract BatchTestProcedures is Test, DeployUtils, FfiUtils, DefaultMarketInput

where

import {DeployUtils} from '../../src/deployments/contracts/utilities/DeployUtils.sol';

You can check all the files marked as mock in cache file

@grandizzy
Copy link
Collaborator Author

Can also just be a side effect of how the codebase is set up with very deep hierarchies

Yeah, most probably many mocks aka contracts under test that extend contracts under src, like for example

contract BatchTestProcedures is Test, DeployUtils, FfiUtils, DefaultMarketInput

where

import {DeployUtils} from '../../src/deployments/contracts/utilities/DeployUtils.sol';

You can check all the files marked as mock in cache file

they also have mocks under src, so this doesn't help either as they won't be subject of preprocessing

@grandizzy grandizzy added T-feature Type: feature C-forge Command: forge labels Mar 6, 2025
@sakulstra
Copy link
Contributor

Let me know if there's sth I can help with on the aave side.
e.g. happy to move the mocks.

I suspect the problem is though that we essentially deploy the whole protocol + periphery on every test, which is not trivial to change.

@grandizzy grandizzy marked this pull request as ready for review March 14, 2025 09:42
@zerosnacks
Copy link
Member

Tested on Solady and Euler's EVC - no issues, added the benchmarks

@grandizzy grandizzy force-pushed the issue-9863 branch 2 times, most recently from 103404d to def0113 Compare April 3, 2025 14:46
mattsse pushed a commit to foundry-rs/compilers that referenced this pull request Apr 7, 2025
Implements a preprocessor allowing us to skip recompiling tests on
non-interface source file changes. See the companion Foundry PR
foundry-rs/foundry#10010 for benchmarks and more
details.

Supersedes #198:
- uses solar AST instead solang-parser to compute interface
representation
- uses solar HIR instead of solc AST to find bytecode dependencies
- handles more edge cases, like deploying with salt/value

Closes #197.

### TODO
- [x] use solar HIR (deps to review and include
paradigmxyz/solar#210)
- [x] unit tests
- [x] opt-in caching changes
- [x] autodetect mocks
- [x] figure out how to parse when building from different dir
- [x] additional testing (tested with uniswap v4-core and simpler
projects)

### Depends on
- [x] merge solar PR (paradigmxyz/solar#210)
- [x] solar release

---------

Co-authored-by: Arsenii Kulikov <[email protected]>
Co-authored-by: zerosnacks <[email protected]>
Co-authored-by: DaniPopes <[email protected]>
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.

lgtm, send it 2

@grandizzy grandizzy merged commit b455c5b into foundry-rs:master Apr 7, 2025
22 checks passed
@grandizzy grandizzy deleted the issue-9863 branch April 7, 2025 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-forge Command: forge T-feature Type: feature
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

feat: optimize compilation through preprocessing and smarter caching
5 participants