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

perf: precompile contracts for faster test runs #14

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: ERC6900 RI Test CI
name: ERC-6900 RI Test CI

on: [pull_request, workflow_dispatch]

Expand Down Expand Up @@ -45,9 +45,9 @@ jobs:

- name: "Lint the contracts"
run: "pnpm lint"
test:
name: Run Forge Tests

test-optimized-test-deep:
name: Run Forge Tests (optimized-test-deep)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -63,13 +63,13 @@ jobs:
run: forge install

- name: Build project
run: forge build
run: FOUNDRY_PROFILE=optimized-build forge build

- name: Run tests
run: FOUNDRY_PROFILE=deep forge test -vvv
run: FOUNDRY_PROFILE=optimized-test-deep forge test -vvv

test-lite:
name: Run Forge Tests [lite build]
test-default:
name: Run Forge Tests (default)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -85,7 +85,7 @@ jobs:
run: forge install

- name: Build project
run: FOUNDRY_PROFILE=lite forge build
run: forge build

- name: Run tests
run: FOUNDRY_PROFILE=lite forge test -vvv
run: forge test -vvv
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Foundry build and cache directories
out/
out-optimized/
cache/
node_modules/

# Coverage
report/
lcov.info
18 changes: 8 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ERC-6900 Ref Implementation
# ERC-6900 Reference Implementation

Reference implementation for [ERC-6900](https://eips.ethereum.org/EIPS/eip-6900). It is an early draft implementation.

Expand All @@ -13,20 +13,18 @@ The implementation includes an upgradable modular account with two plugins (`Sin

Anyone is welcome to submit feedback and/or PRs to improve code or add Plugins.

### Build
### Testing

The default Foundry profile can be used to compile (without IR) and test the entire project. The default profile should be used when generating coverage and debugging.

```bash
forge build

# or use the lite profile to reduce compilation time
FOUNDRY_PROFILE=lite forge build
forge test -vvv
```

### Test
Since IR compilation generates different bytecode, it's useful to test against the contracts compiled via IR. Since compiling the entire project (including the test suite) takes a long time, special profiles can be used to precompile just the source contracts, and have the tests deploy the relevant contracts using those artifacts.

```bash
forge test -vvv

# or use the lite profile to reduce compilation time
FOUNDRY_PROFILE=lite forge test -vvv
FOUNDRY_PROFILE=optimized-build forge build
FOUNDRY_PROFILE=optimized-test forge test -vvv
```
32 changes: 23 additions & 9 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
[profile.default]
solc = '0.8.19'
via_ir = true
via_ir = false
src = 'src'
out = 'out'
test = 'test'
libs = ['lib']
out = 'out'
optimizer = true
optimizer_runs = 10_000
ignored_error_codes = [3628]
fs_permissions = [
{ access = "read", path = "./out-optimized" }
]

[fuzz]
runs = 500
Expand All @@ -17,12 +20,23 @@ runs=500
fail_on_revert = true
depth = 10

[profile.lite]
solc = '0.8.19'
via_ir = false
optimizer = true
optimizer_runs = 10_000
ignored_error_codes = [3628]
[profile.optimized-build]
via_ir = true
test = 'src'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this the line that skips building tests contract?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yup! The alternative is to use --skip test, but that ends up compiling files in the test directory that do not end in t.sol.

out = 'out-optimized'

[profile.optimized-test]
src = 'test'

[profile.optimized-test-deep]
src = 'test'

[profile.optimized-test-deep.fuzz]
runs = 10000

[profile.optimized-test-deep.invariant]
runs = 5000
depth = 32

[profile.deep.fuzz]
runs = 10000
Expand All @@ -43,4 +57,4 @@ goerli = "${RPC_URL_GOERLI}"
mainnet = { key = "${ETHERSCAN_API_KEY}" }
goerli = { key = "${ETHERSCAN_API_KEY}" }

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
21 changes: 0 additions & 21 deletions test/TestUtils.sol

This file was deleted.

7 changes: 3 additions & 4 deletions test/account/AccountLoupe.t.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {Test} from "forge-std/Test.sol";

import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol";

Expand All @@ -23,8 +21,9 @@ import {FunctionReference, FunctionReferenceLib} from "../../src/libraries/Funct
import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol";
import {ComprehensivePlugin} from "../mocks/plugins/ComprehensivePlugin.sol";
import {MockPlugin} from "../mocks/MockPlugin.sol";
import {OptimizedTest} from "../utils/OptimizedTest.sol";

contract AccountLoupeTest is Test {
contract AccountLoupeTest is OptimizedTest {
EntryPoint public entryPoint;
SingleOwnerPlugin public singleOwnerPlugin;
MSCAFactoryFixture public factory;
Expand All @@ -40,7 +39,7 @@ contract AccountLoupeTest is Test {
function setUp() public {
entryPoint = new EntryPoint();

singleOwnerPlugin = new SingleOwnerPlugin();
singleOwnerPlugin = _deploySingleOwnerPlugin();
factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin);
comprehensivePlugin = new ComprehensivePlugin();

Expand Down
7 changes: 3 additions & 4 deletions test/account/AccountReturnData.t.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {Test} from "forge-std/Test.sol";

import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol";

import {IPluginManager} from "../../src/interfaces/IPluginManager.sol";
Expand All @@ -17,9 +15,10 @@ import {
ResultConsumerPlugin
} from "../mocks/plugins/ReturnDataPluginMocks.sol";
import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol";
import {OptimizedTest} from "../utils/OptimizedTest.sol";

// Tests all the different ways that return data can be read from plugins through an account
contract AccountReturnDataTest is Test {
contract AccountReturnDataTest is OptimizedTest {
EntryPoint public entryPoint; // Just to be able to construct the factory
SingleOwnerPlugin public singleOwnerPlugin;
MSCAFactoryFixture public factory;
Expand All @@ -32,7 +31,7 @@ contract AccountReturnDataTest is Test {

function setUp() public {
entryPoint = new EntryPoint();
singleOwnerPlugin = new SingleOwnerPlugin();
singleOwnerPlugin = _deploySingleOwnerPlugin();
factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin);

regularResultContract = new RegularResultContract();
Expand Down
9 changes: 4 additions & 5 deletions test/account/ExecuteFromPluginPermissions.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {Test, console} from "forge-std/Test.sol";
import {console} from "forge-std/Test.sol";

import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol";

Expand All @@ -11,18 +11,17 @@ import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol";
import {FunctionReference} from "../../src/libraries/FunctionReferenceLib.sol";

import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol";

import {Counter} from "../mocks/Counter.sol";
import {ResultCreatorPlugin} from "../mocks/plugins/ReturnDataPluginMocks.sol";

import {
EFPCallerPlugin,
EFPCallerPluginAnyExternal,
EFPPermittedCallHookPlugin,
EFPExternalPermittedCallHookPlugin
} from "../mocks/plugins/ExecFromPluginPermissionsMocks.sol";
import {OptimizedTest} from "../utils/OptimizedTest.sol";

contract ExecuteFromPluginPermissionsTest is Test {
contract ExecuteFromPluginPermissionsTest is OptimizedTest {
Counter public counter1;
Counter public counter2;
Counter public counter3;
Expand All @@ -47,7 +46,7 @@ contract ExecuteFromPluginPermissionsTest is Test {

// Initialize the contracts needed to use the account.
entryPoint = new EntryPoint();
singleOwnerPlugin = new SingleOwnerPlugin();
singleOwnerPlugin = _deploySingleOwnerPlugin();
factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin);

// Initialize the EFP caller plugins, which will attempt to use the permissions system to authorize calls.
Expand Down
7 changes: 3 additions & 4 deletions test/account/ManifestValidity.t.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {Test} from "forge-std/Test.sol";

import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol";

import {IPluginManager} from "../../src/interfaces/IPluginManager.sol";
Expand All @@ -22,8 +20,9 @@ import {
BadHookMagicValue_RuntimeValidationFunction_Plugin,
BadHookMagicValue_PostExecHook_Plugin
} from "../mocks/plugins/ManifestValidityMocks.sol";
import {OptimizedTest} from "../utils/OptimizedTest.sol";

contract ManifestValidityTest is Test {
contract ManifestValidityTest is OptimizedTest {
EntryPoint public entryPoint; // Just to be able to construct the factory
SingleOwnerPlugin public singleOwnerPlugin;
MSCAFactoryFixture public factory;
Expand All @@ -32,7 +31,7 @@ contract ManifestValidityTest is Test {

function setUp() public {
entryPoint = new EntryPoint();
singleOwnerPlugin = new SingleOwnerPlugin();
singleOwnerPlugin = _deploySingleOwnerPlugin();
factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin);

// Create an account with "this" as the owner, so we can execute along the runtime path with regular
Expand Down
9 changes: 5 additions & 4 deletions test/account/UpgradeableModularAccount.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {Test, console} from "forge-std/Test.sol";
import {console} from "forge-std/Test.sol";

import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol";
Expand All @@ -23,8 +23,9 @@ import {Counter} from "../mocks/Counter.sol";
import {MSCAFactoryFixture} from "../mocks/MSCAFactoryFixture.sol";
import {ComprehensivePlugin} from "../mocks/plugins/ComprehensivePlugin.sol";
import {MockPlugin} from "../mocks/MockPlugin.sol";
import {OptimizedTest} from "../utils/OptimizedTest.sol";

contract UpgradeableModularAccountTest is Test {
contract UpgradeableModularAccountTest is OptimizedTest {
using ECDSA for bytes32;

EntryPoint public entryPoint;
Expand Down Expand Up @@ -68,8 +69,8 @@ contract UpgradeableModularAccountTest is Test {
beneficiary = payable(makeAddr("beneficiary"));
vm.deal(beneficiary, 1 wei);

singleOwnerPlugin = new SingleOwnerPlugin();
tokenReceiverPlugin = new TokenReceiverPlugin();
singleOwnerPlugin = _deploySingleOwnerPlugin();
tokenReceiverPlugin = _deployTokenReceiverPlugin();
factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin);

// Compute counterfactual address
Expand Down
7 changes: 3 additions & 4 deletions test/account/ValidationIntersection.t.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {Test} from "forge-std/Test.sol";

import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol";
import {UserOperation} from "@eth-infinitism/account-abstraction/interfaces/UserOperation.sol";

Expand All @@ -18,8 +16,9 @@ import {
MockUserOpValidation2HookPlugin,
MockUserOpValidationPlugin
} from "../mocks/plugins/ValidationPluginMocks.sol";
import {OptimizedTest} from "../utils/OptimizedTest.sol";

contract ValidationIntersectionTest is Test {
contract ValidationIntersectionTest is OptimizedTest {
uint256 internal constant _SIG_VALIDATION_FAILED = 1;

EntryPoint public entryPoint;
Expand All @@ -35,7 +34,7 @@ contract ValidationIntersectionTest is Test {
entryPoint = new EntryPoint();
owner1 = makeAddr("owner1");

SingleOwnerPlugin singleOwnerPlugin = new SingleOwnerPlugin();
SingleOwnerPlugin singleOwnerPlugin = _deploySingleOwnerPlugin();
MSCAFactoryFixture factory = new MSCAFactoryFixture(entryPoint, singleOwnerPlugin);

account1 = factory.createAccount(owner1, 0);
Expand Down
6 changes: 4 additions & 2 deletions test/mocks/MSCAFactoryFixture.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntry
import {UpgradeableModularAccount} from "../../src/account/UpgradeableModularAccount.sol";
import {SingleOwnerPlugin} from "../../src/plugins/owner/SingleOwnerPlugin.sol";

import {OptimizedTest} from "../utils/OptimizedTest.sol";

/**
* @title MSCAFactoryFixture
* @dev a factory that initializes UpgradeableModularAccounts with a single plugin, SingleOwnerPlugin
* intended for unit tests and local development, not for production.
*/
contract MSCAFactoryFixture {
contract MSCAFactoryFixture is OptimizedTest {
UpgradeableModularAccount public accountImplementation;
SingleOwnerPlugin public singleOwnerPlugin;
bytes32 private immutable _PROXY_BYTECODE_HASH;
Expand All @@ -28,7 +30,7 @@ contract MSCAFactoryFixture {

constructor(IEntryPoint _entryPoint, SingleOwnerPlugin _singleOwnerPlugin) {
entryPoint = _entryPoint;
accountImplementation = new UpgradeableModularAccount(_entryPoint);
accountImplementation = _deployUpgradeableModularAccount(_entryPoint);
_PROXY_BYTECODE_HASH = keccak256(
abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(address(accountImplementation), ""))
);
Expand Down
Loading