Commit 78a5c4f8 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

contracts-bedrock: flake fix attempt (#9082)

* contracts-bedrock: flake fix attempt

Progress towards fixing flakes in CI. Using `etch` to set contracts in
state instead of deploying will help to fix the nonce mismatches between
the L1 contract addresses and the L2 genesis that contains L1 contract
addresses.

Developers will need to run `forge clean` to remove artifacts for the
tests to pass after this commit is merged. It enforces a single version
of `FFIInterface` to be compiled instead of it being compiled with
multiple compiler versions. The `vm.getCode` family of cheats fail when
there are multiple compiled versions of the same contract because the
artfact has the compiler version appended to the name of the artifact.

This will also help to improve compiler time since the compiled
contracts do not need to include the compiled bytecode of the deploy and
ffiinterface contracts, the code is loaded dynamically instead of being
deployed with `CREATE`.

* contracts-bedrock: more cleanup

Deletes a dead file that is no longer needed and sets the deploy config
in state using `etch`. `DeployL2` is not used, we should be using the
`superchain-ops` repo for deploying new L2 contracts or deploy them
through L1. Since `DeployL2` used code using solc `0.8.19` (EAS) it
caused multiple versions of the `DeployConfig` to be compiled which
causes headaches when using `vm.getCode`.

* contracts-bedrock: update gas snapshot

* contracts-bedrock: more cleanup

* contracts-bedrock: gas-snapshot

* lint: fix
parent f6480169
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 352278) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 352255)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2950440) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2950462)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 540648) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 540625)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4052841) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4052818)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 442007) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 442029)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3487756) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3487756)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 55367) GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 55367)
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 86629) GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 86651)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68450) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68472)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 68899) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 68909)
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 153493) GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 153504)
\ No newline at end of file \ No newline at end of file
...@@ -53,10 +53,11 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; ...@@ -53,10 +53,11 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
/// Then add a call to that function inside of `run`. Be sure to call the `save` function after each /// Then add a call to that function inside of `run`. Be sure to call the `save` function after each
/// deployment so that hardhat-deploy style artifacts can be generated using a call to `sync()`. /// deployment so that hardhat-deploy style artifacts can be generated using a call to `sync()`.
/// The `CONTRACT_ADDRESSES_PATH` environment variable can be set to a path that contains a JSON file full of /// The `CONTRACT_ADDRESSES_PATH` environment variable can be set to a path that contains a JSON file full of
/// contract name to address pairs. That enables this script to be much more flexible in the way /// contract name to address pairs. That enables this script to be much more flexible in the way it is used.
/// it is used. /// This contract must not have constructor logic because it is set into state using `etch`.
contract Deploy is Deployer { contract Deploy is Deployer {
DeployConfig public cfg; DeployConfig public constant cfg =
DeployConfig(address(uint160(uint256(keccak256(abi.encode("optimism.deployconfig"))))));
using stdJson for string; using stdJson for string;
...@@ -221,7 +222,10 @@ contract Deploy is Deployer { ...@@ -221,7 +222,10 @@ contract Deploy is Deployer {
super.setUp(); super.setUp();
string memory path = string.concat(vm.projectRoot(), "/deploy-config/", deploymentContext, ".json"); string memory path = string.concat(vm.projectRoot(), "/deploy-config/", deploymentContext, ".json");
cfg = new DeployConfig(path); vm.etch(address(cfg), vm.getDeployedCode("DeployConfig.s.sol:DeployConfig"));
vm.label(address(cfg), "DeployConfig");
vm.allowCheatcodes(address(cfg));
cfg.read(path);
console.log("Deploying from %s", deployScript); console.log("Deploying from %s", deployScript);
console.log("Deployment context: %s", deploymentContext); console.log("Deployment context: %s", deploymentContext);
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; pragma solidity 0.8.15;
import { Script } from "forge-std/Script.sol"; import { Script } from "forge-std/Script.sol";
import { console2 as console } from "forge-std/console2.sol"; import { console2 as console } from "forge-std/console2.sol";
...@@ -59,7 +59,7 @@ contract DeployConfig is Script { ...@@ -59,7 +59,7 @@ contract DeployConfig is Script {
uint256 public requiredProtocolVersion; uint256 public requiredProtocolVersion;
uint256 public recommendedProtocolVersion; uint256 public recommendedProtocolVersion;
constructor(string memory _path) { function read(string memory _path) public {
console.log("DeployConfig: reading file %s", _path); console.log("DeployConfig: reading file %s", _path);
try vm.readFile(_path) returns (string memory data) { try vm.readFile(_path) returns (string memory data) {
_json = data; _json = data;
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Deployer } from "./Deployer.sol";
import { DeployConfig } from "./DeployConfig.s.sol";
import { console2 as console } from "forge-std/console2.sol";
import { EAS } from "../src/EAS/EAS.sol";
import { SchemaRegistry } from "../src/EAS/SchemaRegistry.sol";
import { ISchemaRegistry } from "../src/EAS/ISchemaRegistry.sol";
import { Predeploys } from "../src/libraries/Predeploys.sol";
/// @title DeployL2
/// @notice Script used to deploy predeploy implementations to L2.
contract DeployL2 is Deployer {
DeployConfig cfg;
/// @notice The name of the script, used to ensure the right deploy artifacts
/// are used.
function name() public pure override returns (string memory) {
return "DeployL2";
}
function setUp() public override {
super.setUp();
string memory path = string.concat(vm.projectRoot(), "/deploy-config/", deploymentContext, ".json");
cfg = new DeployConfig(path);
console.log("Deploying from %s", deployScript);
console.log("Deployment context: %s", deploymentContext);
}
/// @notice Modifier that wraps a function in broadcasting.
modifier broadcast() {
vm.startBroadcast();
_;
vm.stopBroadcast();
}
/// @notice Deploy the EAS implementation.
function deployEAS() public broadcast returns (address) {
EAS eas = new EAS();
ISchemaRegistry registry = eas.getSchemaRegistry();
require(address(registry) == Predeploys.SCHEMA_REGISTRY, "EAS: invalid SchemaRegistry address");
save("EAS", address(eas));
console.log("EAS deployed at %s", address(eas));
string memory version = eas.version();
console.log("EAS version: %s", version);
return address(eas);
}
/// @notice Deploy the SchemaManager implementation.
function deploySchemaRegistry() public broadcast returns (address) {
SchemaRegistry registry = new SchemaRegistry();
save("SchemaRegistry", address(registry));
console.log("SchemaRegistry deployed at %s", address(registry));
string memory version = registry.version();
console.log("SchemaRegistry version: %s", version);
return address(registry);
}
}
...@@ -6,10 +6,11 @@ import { MerkleTrie } from "src/libraries/trie/MerkleTrie.sol"; ...@@ -6,10 +6,11 @@ import { MerkleTrie } from "src/libraries/trie/MerkleTrie.sol";
import { FFIInterface } from "test/setup/FFIInterface.sol"; import { FFIInterface } from "test/setup/FFIInterface.sol";
contract MerkleTrie_get_Test is Test { contract MerkleTrie_get_Test is Test {
FFIInterface ffi; FFIInterface constant ffi = FFIInterface(address(uint160(uint256(keccak256(abi.encode("optimism.ffi"))))));
function setUp() public { function setUp() public {
ffi = new FFIInterface(); vm.etch(address(ffi), vm.getDeployedCode("FFIInterface.sol:FFIInterface"));
vm.label(address(ffi), "FFIInterface");
} }
function test_get_validProof1_succeeds() external { function test_get_validProof1_succeeds() external {
......
...@@ -8,13 +8,13 @@ import { FFIInterface } from "test/setup/FFIInterface.sol"; ...@@ -8,13 +8,13 @@ import { FFIInterface } from "test/setup/FFIInterface.sol";
/// @title CommonTest /// @title CommonTest
/// @dev An extenstion to `Test` that sets up the optimism smart contracts. /// @dev An extenstion to `Test` that sets up the optimism smart contracts.
contract CommonTest is Setup, Test, Events { contract CommonTest is Test, Setup, Events {
address alice; address alice;
address bob; address bob;
bytes32 constant nonZeroHash = keccak256(abi.encode("NON_ZERO")); bytes32 constant nonZeroHash = keccak256(abi.encode("NON_ZERO"));
FFIInterface ffi; FFIInterface constant ffi = FFIInterface(address(uint160(uint256(keccak256(abi.encode("optimism.ffi"))))));
function setUp() public virtual override { function setUp() public virtual override {
alice = makeAddr("alice"); alice = makeAddr("alice");
...@@ -23,8 +23,8 @@ contract CommonTest is Setup, Test, Events { ...@@ -23,8 +23,8 @@ contract CommonTest is Setup, Test, Events {
vm.deal(bob, 10000 ether); vm.deal(bob, 10000 ether);
Setup.setUp(); Setup.setUp();
vm.prank(deployer); vm.etch(address(ffi), vm.getDeployedCode("FFIInterface.sol:FFIInterface"));
ffi = new FFIInterface(); vm.label(address(ffi), "FFIInterface");
// Make sure the base fee is non zero // Make sure the base fee is non zero
vm.fee(1 gwei); vm.fee(1 gwei);
...@@ -36,7 +36,7 @@ contract CommonTest is Setup, Test, Events { ...@@ -36,7 +36,7 @@ contract CommonTest is Setup, Test, Events {
// Deploy L1 // Deploy L1
Setup.L1(); Setup.L1();
// Deploy L2 // Deploy L2
Setup.L2({ cfg: deploy.cfg() }); Setup.L2();
} }
/// @dev Helper function that wraps `TransactionDeposited` event. /// @dev Helper function that wraps `TransactionDeposited` event.
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; pragma solidity 0.8.15;
import { Types } from "src/libraries/Types.sol"; import { Types } from "src/libraries/Types.sol";
import { Vm } from "forge-std/Vm.sol"; import { Vm } from "forge-std/Vm.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
/// @title FFIInterface /// @title FFIInterface
/// @notice This contract is set into state using `etch` and therefore must not have constructor logic.
/// It also MUST be compiled with `0.8.15` because `vm.getDeployedCode` will break if there
/// are multiple artifacts for different compiler versions.
contract FFIInterface { contract FFIInterface {
Vm internal constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); Vm internal constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
......
...@@ -38,10 +38,12 @@ import { SuperchainConfig } from "src/L1/SuperchainConfig.sol"; ...@@ -38,10 +38,12 @@ import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
/// up behind proxies. In the future we will migrate to importing the genesis JSON /// up behind proxies. In the future we will migrate to importing the genesis JSON
/// file that is created to set up the L2 contracts instead of setting them up manually. /// file that is created to set up the L2 contracts instead of setting them up manually.
contract Setup { contract Setup {
/// @notice The address of the foundry Vm contract.
Vm private constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); Vm private constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
Deploy internal deploy; /// @notice The address of the Deploy contract. Set into state with `etch` to avoid
address deployer = address(0xd3607); /// mutating any nonces. MUST not have constructor logic.
Deploy internal constant deploy = Deploy(address(uint160(uint256(keccak256(abi.encode("optimism.deploy"))))));
OptimismPortal optimismPortal; OptimismPortal optimismPortal;
L2OutputOracle l2OutputOracle; L2OutputOracle l2OutputOracle;
...@@ -77,21 +79,11 @@ contract Setup { ...@@ -77,21 +79,11 @@ contract Setup {
/// will also need to include the bytecode for the Deploy contract. /// will also need to include the bytecode for the Deploy contract.
/// This is a hack as we are pushing solidity to the edge. /// This is a hack as we are pushing solidity to the edge.
function setUp() public virtual { function setUp() public virtual {
deploy = Deploy(_create(vm.getCode("Deploy.s.sol:Deploy"))); vm.etch(address(deploy), vm.getDeployedCode("Deploy.s.sol:Deploy"));
vm.allowCheatcodes(address(deploy));
deploy.setUp(); deploy.setUp();
} }
/// @dev Simple wrapper around the `create` opcode that uses a particular
/// deployer account.
function _create(bytes memory _code) internal returns (address addr_) {
vm.deal(deployer, 1 ether);
vm.prank(deployer);
assembly {
addr_ := create(0, add(_code, 0x20), mload(_code))
}
require(addr_ != address(0), "Setup: cannot create");
}
/// @dev Sets up the L1 contracts. /// @dev Sets up the L1 contracts.
function L1() public { function L1() public {
// Set the deterministic deployer in state to ensure that it is there // Set the deterministic deployer in state to ensure that it is there
...@@ -137,7 +129,7 @@ contract Setup { ...@@ -137,7 +129,7 @@ contract Setup {
} }
/// @dev Sets up the L2 contracts. Depends on `L1()` being called first. /// @dev Sets up the L2 contracts. Depends on `L1()` being called first.
function L2(DeployConfig cfg) public { function L2() public {
string memory allocsPath = string.concat(vm.projectRoot(), "/.testdata/genesis.json"); string memory allocsPath = string.concat(vm.projectRoot(), "/.testdata/genesis.json");
if (vm.isFile(allocsPath) == false) { if (vm.isFile(allocsPath) == false) {
string[] memory args = new string[](3); string[] memory args = new string[](3);
...@@ -155,7 +147,7 @@ contract Setup { ...@@ -155,7 +147,7 @@ contract Setup {
vm.loadAllocs(allocsPath); vm.loadAllocs(allocsPath);
// Set the governance token's owner to be the final system owner // Set the governance token's owner to be the final system owner
address finalSystemOwner = cfg.finalSystemOwner(); address finalSystemOwner = deploy.cfg().finalSystemOwner();
vm.prank(governanceToken.owner()); vm.prank(governanceToken.owner());
governanceToken.transferOwnership(finalSystemOwner); governanceToken.transferOwnership(finalSystemOwner);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment