Commit 48263376 authored by Sebastian Stammler's avatar Sebastian Stammler Committed by GitHub

contracts: Make L2 genesis script configurable (#10764)

* contracts: Make L2 genesis script configurable

* contracts: Read latest fork from deploy config in L2 genesis script

* contracts: add README entry for new L2 genesis script env vars

* address review
parent 8e9baf53
...@@ -243,25 +243,25 @@ jobs: ...@@ -243,25 +243,25 @@ jobs:
- "packages/contracts-bedrock/tsconfig.tsbuildinfo" - "packages/contracts-bedrock/tsconfig.tsbuildinfo"
- "packages/contracts-bedrock/tsconfig.build.tsbuildinfo" - "packages/contracts-bedrock/tsconfig.build.tsbuildinfo"
- ".devnet/allocs-l1.json" - ".devnet/allocs-l1.json"
- ".devnet/allocs-l2.json"
- ".devnet/allocs-l2-delta.json" - ".devnet/allocs-l2-delta.json"
- ".devnet/allocs-l2-ecotone.json" - ".devnet/allocs-l2-ecotone.json"
- ".devnet/allocs-l2-fjord.json"
- ".devnet/addresses.json" - ".devnet/addresses.json"
- ".devnet-l2oo/allocs-l1.json" - ".devnet-l2oo/allocs-l1.json"
- ".devnet-l2oo/addresses.json" - ".devnet-l2oo/addresses.json"
- ".devnet-l2oo/allocs-l2.json"
- ".devnet-l2oo/allocs-l2-delta.json" - ".devnet-l2oo/allocs-l2-delta.json"
- ".devnet-l2oo/allocs-l2-ecotone.json" - ".devnet-l2oo/allocs-l2-ecotone.json"
- ".devnet-l2oo/allocs-l2-fjord.json"
- ".devnet-plasma/allocs-l1.json" - ".devnet-plasma/allocs-l1.json"
- ".devnet-plasma/addresses.json" - ".devnet-plasma/addresses.json"
- ".devnet-plasma/allocs-l2.json"
- ".devnet-plasma/allocs-l2-delta.json" - ".devnet-plasma/allocs-l2-delta.json"
- ".devnet-plasma/allocs-l2-ecotone.json" - ".devnet-plasma/allocs-l2-ecotone.json"
- ".devnet-plasma/allocs-l2-fjord.json"
- ".devnet-plasma-generic/allocs-l1.json" - ".devnet-plasma-generic/allocs-l1.json"
- ".devnet-plasma-generic/addresses.json" - ".devnet-plasma-generic/addresses.json"
- ".devnet-plasma-generic/allocs-l2.json"
- ".devnet-plasma-generic/allocs-l2-delta.json" - ".devnet-plasma-generic/allocs-l2-delta.json"
- ".devnet-plasma-generic/allocs-l2-ecotone.json" - ".devnet-plasma-generic/allocs-l2-ecotone.json"
- ".devnet-plasma-generic/allocs-l2-fjord.json"
- "packages/contracts-bedrock/deploy-config/devnetL1.json" - "packages/contracts-bedrock/deploy-config/devnetL1.json"
- "packages/contracts-bedrock/deployments/devnetL1" - "packages/contracts-bedrock/deployments/devnetL1"
- notify-failures-on-develop - notify-failures-on-develop
...@@ -928,9 +928,9 @@ jobs: ...@@ -928,9 +928,9 @@ jobs:
name: Load devnet-allocs name: Load devnet-allocs
command: | command: |
mkdir -p .devnet mkdir -p .devnet
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2.json .devnet/allocs-l2.json
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-delta.json .devnet/allocs-l2-delta.json cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-delta.json .devnet/allocs-l2-delta.json
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-ecotone.json .devnet/allocs-l2-ecotone.json cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-ecotone.json .devnet/allocs-l2-ecotone.json
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-fjord.json .devnet/allocs-l2-fjord.json
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l1.json .devnet/allocs-l1.json cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l1.json .devnet/allocs-l1.json
cp /tmp/workspace/.devnet<<parameters.variant>>/addresses.json .devnet/addresses.json cp /tmp/workspace/.devnet<<parameters.variant>>/addresses.json .devnet/addresses.json
cp /tmp/workspace/packages/contracts-bedrock/deploy-config/devnetL1.json packages/contracts-bedrock/deploy-config/devnetL1.json cp /tmp/workspace/packages/contracts-bedrock/deploy-config/devnetL1.json packages/contracts-bedrock/deploy-config/devnetL1.json
...@@ -1113,9 +1113,9 @@ jobs: ...@@ -1113,9 +1113,9 @@ jobs:
- persist_to_workspace: - persist_to_workspace:
root: . root: .
paths: paths:
- ".devnet/allocs-l2.json"
- ".devnet/allocs-l2-delta.json" - ".devnet/allocs-l2-delta.json"
- ".devnet/allocs-l2-ecotone.json" - ".devnet/allocs-l2-ecotone.json"
- ".devnet/allocs-l2-fjord.json"
- ".devnet/allocs-l1.json" - ".devnet/allocs-l1.json"
- ".devnet/addresses.json" - ".devnet/addresses.json"
- "packages/contracts-bedrock/deploy-config/devnetL1.json" - "packages/contracts-bedrock/deploy-config/devnetL1.json"
......
...@@ -26,6 +26,9 @@ parser.add_argument('--test', help='Tests the deployment, must already be deploy ...@@ -26,6 +26,9 @@ parser.add_argument('--test', help='Tests the deployment, must already be deploy
log = logging.getLogger() log = logging.getLogger()
# Global constants
FORKS = ["delta", "ecotone", "fjord"]
# Global environment variables # Global environment variables
DEVNET_NO_BUILD = os.getenv('DEVNET_NO_BUILD') == "true" DEVNET_NO_BUILD = os.getenv('DEVNET_NO_BUILD') == "true"
DEVNET_L2OO = os.getenv('DEVNET_L2OO') == "true" DEVNET_L2OO = os.getenv('DEVNET_L2OO') == "true"
...@@ -171,9 +174,9 @@ def devnet_l2_allocs(paths): ...@@ -171,9 +174,9 @@ def devnet_l2_allocs(paths):
# For the previous forks, and the latest fork (default, thus empty prefix), # For the previous forks, and the latest fork (default, thus empty prefix),
# move the forge-dumps into place as .devnet allocs. # move the forge-dumps into place as .devnet allocs.
for suffix in ["-delta", "-ecotone", ""]: for fork in FORKS:
input_path = pjoin(paths.contracts_bedrock_dir, f"state-dump-901{suffix}.json") input_path = pjoin(paths.contracts_bedrock_dir, f"state-dump-901-{fork}.json")
output_path = pjoin(paths.devnet_dir, f'allocs-l2{suffix}.json') output_path = pjoin(paths.devnet_dir, f'allocs-l2-{fork}.json')
shutil.move(src=input_path, dst=output_path) shutil.move(src=input_path, dst=output_path)
log.info("Generated L2 allocs: "+output_path) log.info("Generated L2 allocs: "+output_path)
...@@ -218,7 +221,7 @@ def devnet_deploy(paths): ...@@ -218,7 +221,7 @@ def devnet_deploy(paths):
log.info('L2 genesis and rollup configs already generated.') log.info('L2 genesis and rollup configs already generated.')
else: else:
log.info('Generating L2 genesis and rollup configs.') log.info('Generating L2 genesis and rollup configs.')
l2_allocs_path = pjoin(paths.devnet_dir, 'allocs-l2.json') l2_allocs_path = pjoin(paths.devnet_dir, f'allocs-l2-{FORKS[-1]}.json')
if os.path.exists(l2_allocs_path) == False or DEVNET_L2OO == True: if os.path.exists(l2_allocs_path) == False or DEVNET_L2OO == True:
# Also regenerate if L2OO. # Also regenerate if L2OO.
# The L2OO flag may affect the L1 deployments addresses, which may affect the L2 genesis. # The L2OO flag may affect the L1 deployments addresses, which may affect the L2 genesis.
......
...@@ -24,7 +24,7 @@ type L2AllocsMode string ...@@ -24,7 +24,7 @@ type L2AllocsMode string
const ( const (
L2AllocsDelta L2AllocsMode = "delta" L2AllocsDelta L2AllocsMode = "delta"
L2AllocsEcotone L2AllocsMode = "ecotone" L2AllocsEcotone L2AllocsMode = "ecotone"
L2AllocsFjord L2AllocsMode = "" // the default in solidity scripting / testing L2AllocsFjord L2AllocsMode = "fjord"
) )
var ( var (
......
...@@ -113,10 +113,7 @@ func init() { ...@@ -113,10 +113,7 @@ func init() {
} }
l2Allocs = make(map[genesis.L2AllocsMode]*genesis.ForgeAllocs) l2Allocs = make(map[genesis.L2AllocsMode]*genesis.ForgeAllocs)
mustL2Allocs := func(mode genesis.L2AllocsMode) { mustL2Allocs := func(mode genesis.L2AllocsMode) {
name := "allocs-l2" name := "allocs-l2-" + string(mode)
if mode != "" {
name += "-" + string(mode)
}
allocs, err := genesis.LoadForgeAllocs(filepath.Join(l2AllocsDir, name+".json")) allocs, err := genesis.LoadForgeAllocs(filepath.Join(l2AllocsDir, name+".json"))
if err != nil { if err != nil {
panic(err) panic(err)
......
...@@ -319,6 +319,18 @@ STATE_DUMP_PATH=<PATH_TO_WRITE_L2_ALLOCS> \ ...@@ -319,6 +319,18 @@ STATE_DUMP_PATH=<PATH_TO_WRITE_L2_ALLOCS> \
Create or modify a file `<network-name>.json` inside of the [`deploy-config`](./deploy-config/) folder. Create or modify a file `<network-name>.json` inside of the [`deploy-config`](./deploy-config/) folder.
Use the env var `DEPLOY_CONFIG_PATH` to use a particular deploy config file at runtime. Use the env var `DEPLOY_CONFIG_PATH` to use a particular deploy config file at runtime.
The script will read the latest active fork from the deploy config and the L2 genesis allocs generated will be
compatible with this fork. The automatically detected fork can be overwritten by setting the environment variable
`FORK` either to the lower-case fork name (currently `delta`, `ecotone`, or `fjord`) or to `latest`, which will select
the latest fork available (currently `fjord`).
By default, the script will dump the L2 genesis allocs of the detected or selected fork only, to the file at `STATE_DUMP_PATH`.
The optional environment variable `OUTPUT_MODE` allows to modify this behavior by setting it to one of the following values:
* `latest` (default) - only dump the selected fork's allocs.
* `all` - also dump all intermediary fork's allocs. This only works if `STATE_DUMP_PATH` is _not_ set. In this case, all allocs
will be written to files `/state-dump-<fork>.json`. Another path cannot currently be specified for this use case.
* `none` - won't dump any allocs. Only makes sense for internal test usage.
#### Custom Gas Token #### Custom Gas Token
The Custom Gas Token feature is a Beta feature of the MIT licensed OP Stack. The Custom Gas Token feature is a Beta feature of the MIT licensed OP Stack.
......
...@@ -3,6 +3,56 @@ pragma solidity ^0.8.0; ...@@ -3,6 +3,56 @@ pragma solidity ^0.8.0;
import { Vm, VmSafe } from "forge-std/Vm.sol"; import { Vm, VmSafe } from "forge-std/Vm.sol";
/// @notice Enum representing different ways of outputting genesis allocs.
/// @custom:value NONE No output, used in internal tests.
/// @custom:value LATEST Output allocs only for latest fork.
/// @custom:value ALL Output allocs for all intermediary forks.
enum OutputMode {
NONE,
LATEST,
ALL
}
library OutputModeUtils {
function toString(OutputMode _mode) internal pure returns (string memory) {
if (_mode == OutputMode.NONE) {
return "none";
} else if (_mode == OutputMode.LATEST) {
return "latest";
} else if (_mode == OutputMode.ALL) {
return "all";
} else {
return "unknown";
}
}
}
/// @notice Enum of forks available for selection when generating genesis allocs.
enum Fork {
NONE,
DELTA,
ECOTONE,
FJORD
}
Fork constant LATEST_FORK = Fork.FJORD;
library ForkUtils {
function toString(Fork _fork) internal pure returns (string memory) {
if (_fork == Fork.NONE) {
return "none";
} else if (_fork == Fork.DELTA) {
return "delta";
} else if (_fork == Fork.ECOTONE) {
return "ecotone";
} else if (_fork == Fork.FJORD) {
return "fjord";
} else {
return "unknown";
}
}
}
/// @title Config /// @title Config
/// @notice Contains all env var based config. Add any new env var parsing to this file /// @notice Contains all env var based config. Add any new env var parsing to this file
/// to ensure that all config is in a single place. /// to ensure that all config is in a single place.
...@@ -67,4 +117,44 @@ library Config { ...@@ -67,4 +117,44 @@ library Config {
function drippieOwnerPrivateKey() internal view returns (uint256 _env) { function drippieOwnerPrivateKey() internal view returns (uint256 _env) {
_env = vm.envUint("DRIPPIE_OWNER_PRIVATE_KEY"); _env = vm.envUint("DRIPPIE_OWNER_PRIVATE_KEY");
} }
/// @notice Returns the OutputMode for genesis allocs generation.
/// It reads the mode from the environment variable OUTPUT_MODE.
/// If it is unset, OutputMode.ALL is returned.
function outputMode() internal view returns (OutputMode) {
string memory modeStr = vm.envOr("OUTPUT_MODE", string("latest"));
bytes32 modeHash = keccak256(bytes(modeStr));
if (modeHash == keccak256(bytes("none"))) {
return OutputMode.NONE;
} else if (modeHash == keccak256(bytes("latest"))) {
return OutputMode.LATEST;
} else if (modeHash == keccak256(bytes("all"))) {
return OutputMode.ALL;
} else {
revert(string.concat("Config: unknown output mode: ", modeStr));
}
}
/// @notice Returns the latest fork to use for genesis allocs generation.
/// It reads the fork from the environment variable FORK. If it is
/// unset, NONE is returned.
/// If set to the special value "latest", the latest fork is returned.
function fork() internal view returns (Fork) {
string memory forkStr = vm.envOr("FORK", string(""));
if (bytes(forkStr).length == 0) {
return Fork.NONE;
}
bytes32 forkHash = keccak256(bytes(forkStr));
if (forkHash == keccak256(bytes("latest"))) {
return LATEST_FORK;
} else if (forkHash == keccak256(bytes("delta"))) {
return Fork.DELTA;
} else if (forkHash == keccak256(bytes("ecotone"))) {
return Fork.ECOTONE;
} else if (forkHash == keccak256(bytes("fjord"))) {
return Fork.FJORD;
} else {
revert(string.concat("Config: unknown fork: ", forkStr));
}
}
} }
...@@ -7,12 +7,19 @@ import { stdJson } from "forge-std/StdJson.sol"; ...@@ -7,12 +7,19 @@ import { stdJson } from "forge-std/StdJson.sol";
import { Executables } from "scripts/Executables.sol"; import { Executables } from "scripts/Executables.sol";
import { Process } from "scripts/libraries/Process.sol"; import { Process } from "scripts/libraries/Process.sol";
import { Chains } from "scripts/Chains.sol"; import { Chains } from "scripts/Chains.sol";
import { Config, Fork, ForkUtils } from "scripts/Config.sol";
/// @title DeployConfig /// @title DeployConfig
/// @notice Represents the configuration required to deploy the system. It is expected /// @notice Represents the configuration required to deploy the system. It is expected
/// to read the file from JSON. A future improvement would be to have fallback /// to read the file from JSON. A future improvement would be to have fallback
/// values if they are not defined in the JSON themselves. /// values if they are not defined in the JSON themselves.
contract DeployConfig is Script { contract DeployConfig is Script {
using stdJson for string;
using ForkUtils for Fork;
/// @notice Represents an unset offset value, as opposed to 0, which denotes no-offset.
uint256 constant NULL_OFFSET = type(uint256).max;
string internal _json; string internal _json;
address public finalSystemOwner; address public finalSystemOwner;
...@@ -20,6 +27,9 @@ contract DeployConfig is Script { ...@@ -20,6 +27,9 @@ contract DeployConfig is Script {
uint256 public l1ChainID; uint256 public l1ChainID;
uint256 public l2ChainID; uint256 public l2ChainID;
uint256 public l2BlockTime; uint256 public l2BlockTime;
uint256 public l2GenesisDeltaTimeOffset;
uint256 public l2GenesisEcotoneTimeOffset;
uint256 public l2GenesisFjordTimeOffset;
uint256 public maxSequencerDrift; uint256 public maxSequencerDrift;
uint256 public sequencerWindowSize; uint256 public sequencerWindowSize;
uint256 public channelTimeout; uint256 public channelTimeout;
...@@ -94,6 +104,11 @@ contract DeployConfig is Script { ...@@ -94,6 +104,11 @@ contract DeployConfig is Script {
l1ChainID = stdJson.readUint(_json, "$.l1ChainID"); l1ChainID = stdJson.readUint(_json, "$.l1ChainID");
l2ChainID = stdJson.readUint(_json, "$.l2ChainID"); l2ChainID = stdJson.readUint(_json, "$.l2ChainID");
l2BlockTime = stdJson.readUint(_json, "$.l2BlockTime"); l2BlockTime = stdJson.readUint(_json, "$.l2BlockTime");
l2GenesisDeltaTimeOffset = _readOr(_json, "$.l2GenesisDeltaTimeOffset", NULL_OFFSET);
l2GenesisEcotoneTimeOffset = _readOr(_json, "$.l2GenesisEcotoneTimeOffset", NULL_OFFSET);
l2GenesisFjordTimeOffset = _readOr(_json, "$.l2GenesisFjordTimeOffset", NULL_OFFSET);
maxSequencerDrift = stdJson.readUint(_json, "$.maxSequencerDrift"); maxSequencerDrift = stdJson.readUint(_json, "$.maxSequencerDrift");
sequencerWindowSize = stdJson.readUint(_json, "$.sequencerWindowSize"); sequencerWindowSize = stdJson.readUint(_json, "$.sequencerWindowSize");
channelTimeout = stdJson.readUint(_json, "$.channelTimeout"); channelTimeout = stdJson.readUint(_json, "$.channelTimeout");
...@@ -161,6 +176,18 @@ contract DeployConfig is Script { ...@@ -161,6 +176,18 @@ contract DeployConfig is Script {
useInterop = _readOr(_json, "$.useInterop", false); useInterop = _readOr(_json, "$.useInterop", false);
} }
function fork() public view returns (Fork fork_) {
// let env var take precedence
fork_ = Config.fork();
if (fork_ == Fork.NONE) {
// Will revert if no deploy config can be found either.
fork_ = latestGenesisFork();
console.log("DeployConfig: using deploy config fork: %s", fork_.toString());
} else {
console.log("DeployConfig: using env var fork: %s", fork_.toString());
}
}
function l1StartingBlockTag() public returns (bytes32) { function l1StartingBlockTag() public returns (bytes32) {
try vm.parseJsonBytes32(_json, "$.l1StartingBlockTag") returns (bytes32 tag) { try vm.parseJsonBytes32(_json, "$.l1StartingBlockTag") returns (bytes32 tag) {
return tag; return tag;
...@@ -215,6 +242,17 @@ contract DeployConfig is Script { ...@@ -215,6 +242,17 @@ contract DeployConfig is Script {
customGasTokenAddress = _token; customGasTokenAddress = _token;
} }
function latestGenesisFork() internal view returns (Fork) {
if (l2GenesisFjordTimeOffset == 0) {
return Fork.FJORD;
} else if (l2GenesisEcotoneTimeOffset == 0) {
return Fork.ECOTONE;
} else if (l2GenesisDeltaTimeOffset == 0) {
return Fork.DELTA;
}
revert("DeployConfig: no supported fork active at genesis");
}
function _getBlockByTag(string memory _tag) internal returns (bytes32) { function _getBlockByTag(string memory _tag) internal returns (bytes32) {
string[] memory cmd = new string[](3); string[] memory cmd = new string[](3);
cmd[0] = Executables.bash; cmd[0] = Executables.bash;
...@@ -225,15 +263,20 @@ contract DeployConfig is Script { ...@@ -225,15 +263,20 @@ contract DeployConfig is Script {
} }
function _readOr(string memory json, string memory key, bool defaultValue) internal view returns (bool) { function _readOr(string memory json, string memory key, bool defaultValue) internal view returns (bool) {
return vm.keyExists(json, key) ? stdJson.readBool(json, key) : defaultValue; return vm.keyExistsJson(json, key) ? json.readBool(key) : defaultValue;
} }
function _readOr(string memory json, string memory key, uint256 defaultValue) internal view returns (uint256) { function _readOr(string memory json, string memory key, uint256 defaultValue) internal view returns (uint256) {
return vm.keyExists(json, key) ? stdJson.readUint(json, key) : defaultValue; return (vm.keyExistsJson(json, key) && !_isNull(json, key)) ? json.readUint(key) : defaultValue;
} }
function _readOr(string memory json, string memory key, address defaultValue) internal view returns (address) { function _readOr(string memory json, string memory key, address defaultValue) internal view returns (address) {
return vm.keyExists(json, key) ? stdJson.readAddress(json, key) : defaultValue; return vm.keyExistsJson(json, key) ? json.readAddress(key) : defaultValue;
}
function _isNull(string memory json, string memory key) internal pure returns (bool) {
string memory value = json.readString(key);
return (keccak256(bytes(value)) == keccak256(bytes("null")));
} }
function _readOr( function _readOr(
...@@ -245,6 +288,6 @@ contract DeployConfig is Script { ...@@ -245,6 +288,6 @@ contract DeployConfig is Script {
view view
returns (string memory) returns (string memory)
{ {
return vm.keyExists(json, key) ? stdJson.readString(json, key) : defaultValue; return vm.keyExists(json, key) ? json.readString(key) : defaultValue;
} }
} }
...@@ -5,7 +5,7 @@ import { Script } from "forge-std/Script.sol"; ...@@ -5,7 +5,7 @@ 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";
import { Deployer } from "scripts/Deployer.sol"; import { Deployer } from "scripts/Deployer.sol";
import { Config } from "scripts/Config.sol"; import { Config, OutputMode, OutputModeUtils, Fork, ForkUtils, LATEST_FORK } from "scripts/Config.sol";
import { Artifacts } from "scripts/Artifacts.s.sol"; import { Artifacts } from "scripts/Artifacts.s.sol";
import { DeployConfig } from "scripts/DeployConfig.s.sol"; import { DeployConfig } from "scripts/DeployConfig.s.sol";
import { Predeploys } from "src/libraries/Predeploys.sol"; import { Predeploys } from "src/libraries/Predeploys.sol";
...@@ -37,20 +37,6 @@ struct L1Dependencies { ...@@ -37,20 +37,6 @@ struct L1Dependencies {
address payable l1ERC721BridgeProxy; address payable l1ERC721BridgeProxy;
} }
/// @notice Enum representing different ways of outputting genesis allocs.
/// @custom:value DEFAULT_LATEST Represents only latest L2 allocs, written to output path.
/// @custom:value LOCAL_LATEST Represents latest L2 allocs, not output anywhere, but kept in-process.
/// @custom:value LOCAL_ECOTONE Represents Ecotone-upgrade L2 allocs, not output anywhere, but kept in-process.
/// @custom:value LOCAL_DELTA Represents Delta-upgrade L2 allocs, not output anywhere, but kept in-process.
/// @custom:value OUTPUT_ALL Represents creation of one L2 allocs file for every upgrade.
enum OutputMode {
DEFAULT_LATEST,
LOCAL_LATEST,
LOCAL_ECOTONE,
LOCAL_DELTA,
OUTPUT_ALL
}
/// @title L2Genesis /// @title L2Genesis
/// @notice Generates the genesis state for the L2 network. /// @notice Generates the genesis state for the L2 network.
/// The following safety invariants are used when setting state: /// The following safety invariants are used when setting state:
...@@ -59,6 +45,9 @@ enum OutputMode { ...@@ -59,6 +45,9 @@ enum OutputMode {
/// 2. A contract must be deployed using the `new` syntax if there are immutables in the code. /// 2. A contract must be deployed using the `new` syntax if there are immutables in the code.
/// Any other side effects from the init code besides setting the immutables must be cleaned up afterwards. /// Any other side effects from the init code besides setting the immutables must be cleaned up afterwards.
contract L2Genesis is Deployer { contract L2Genesis is Deployer {
using ForkUtils for Fork;
using OutputModeUtils for OutputMode;
uint256 public constant PRECOMPILE_COUNT = 256; uint256 public constant PRECOMPILE_COUNT = 256;
uint80 internal constant DEV_ACCOUNT_FUND_AMT = 10_000 ether; uint80 internal constant DEV_ACCOUNT_FUND_AMT = 10_000 ether;
...@@ -120,7 +109,7 @@ contract L2Genesis is Deployer { ...@@ -120,7 +109,7 @@ contract L2Genesis is Deployer {
/// Sets the precompiles, proxies, and the implementation accounts to be `vm.dumpState` /// Sets the precompiles, proxies, and the implementation accounts to be `vm.dumpState`
/// to generate a L2 genesis alloc. /// to generate a L2 genesis alloc.
function runWithStateDump() public { function runWithStateDump() public {
runWithOptions(OutputMode.DEFAULT_LATEST, artifactDependencies()); runWithOptions(Config.outputMode(), cfg.fork(), artifactDependencies());
} }
/// @notice Alias for `runWithStateDump` so that no `--sig` needs to be specified. /// @notice Alias for `runWithStateDump` so that no `--sig` needs to be specified.
...@@ -130,11 +119,18 @@ contract L2Genesis is Deployer { ...@@ -130,11 +119,18 @@ contract L2Genesis is Deployer {
/// @notice This is used by op-e2e to have a version of the L2 allocs for each upgrade. /// @notice This is used by op-e2e to have a version of the L2 allocs for each upgrade.
function runWithAllUpgrades() public { function runWithAllUpgrades() public {
runWithOptions(OutputMode.OUTPUT_ALL, artifactDependencies()); runWithOptions(OutputMode.ALL, LATEST_FORK, artifactDependencies());
}
/// @notice This is used by foundry tests to enable the latest fork with the
/// given L1 dependencies.
function runWithLatestLocal(L1Dependencies memory _l1Dependencies) public {
runWithOptions(OutputMode.NONE, LATEST_FORK, _l1Dependencies);
} }
/// @notice Build the L2 genesis. /// @notice Build the L2 genesis.
function runWithOptions(OutputMode _mode, L1Dependencies memory _l1Dependencies) public { function runWithOptions(OutputMode _mode, Fork _fork, L1Dependencies memory _l1Dependencies) public {
console.log("L2Genesis: outputMode: %s, fork: %s", _mode.toString(), _fork.toString());
vm.startPrank(deployer); vm.startPrank(deployer);
vm.chainId(cfg.l2ChainID()); vm.chainId(cfg.l2ChainID());
...@@ -147,28 +143,30 @@ contract L2Genesis is Deployer { ...@@ -147,28 +143,30 @@ contract L2Genesis is Deployer {
} }
vm.stopPrank(); vm.stopPrank();
// Genesis is "complete" at this point, but some hardfork activation steps remain. if (writeForkGenesisAllocs(_fork, Fork.DELTA, _mode)) {
// Depending on the "Output Mode" we perform the activations and output the necessary state dumps.
if (_mode == OutputMode.LOCAL_DELTA) {
return; return;
} }
if (_mode == OutputMode.OUTPUT_ALL) {
writeGenesisAllocs(Config.stateDumpPath("-delta"));
}
activateEcotone(); activateEcotone();
if (_mode == OutputMode.LOCAL_ECOTONE) { if (writeForkGenesisAllocs(_fork, Fork.ECOTONE, _mode)) {
return; return;
} }
if (_mode == OutputMode.OUTPUT_ALL) {
writeGenesisAllocs(Config.stateDumpPath("-ecotone"));
}
activateFjord(); activateFjord();
if (_mode == OutputMode.OUTPUT_ALL || _mode == OutputMode.DEFAULT_LATEST) { if (writeForkGenesisAllocs(_fork, Fork.FJORD, _mode)) {
writeGenesisAllocs(Config.stateDumpPath("")); return;
}
}
function writeForkGenesisAllocs(Fork _latest, Fork _current, OutputMode _mode) internal returns (bool isLatest_) {
if (_mode == OutputMode.ALL || _latest == _current && _mode == OutputMode.LATEST) {
string memory suffix = string.concat("-", _current.toString());
writeGenesisAllocs(Config.stateDumpPath(suffix));
}
if (_latest == _current) {
isLatest_ = true;
} }
} }
......
...@@ -3,7 +3,7 @@ pragma solidity 0.8.15; ...@@ -3,7 +3,7 @@ pragma solidity 0.8.15;
// Testing utilities // Testing utilities
import { CommonTest } from "test/setup/CommonTest.sol"; import { CommonTest } from "test/setup/CommonTest.sol";
import { OutputMode } from "scripts/L2Genesis.s.sol"; import { Fork } from "scripts/Config.sol";
// Libraries // Libraries
import { Encoding } from "src/libraries/Encoding.sol"; import { Encoding } from "src/libraries/Encoding.sol";
...@@ -39,7 +39,7 @@ contract GasPriceOracleBedrock_Test is GasPriceOracle_Test { ...@@ -39,7 +39,7 @@ contract GasPriceOracleBedrock_Test is GasPriceOracle_Test {
/// @dev Sets up the test suite. /// @dev Sets up the test suite.
function setUp() public virtual override { function setUp() public virtual override {
// The gasPriceOracle tests rely on an L2 genesis that is not past Ecotone. // The gasPriceOracle tests rely on an L2 genesis that is not past Ecotone.
l2OutputMode = OutputMode.LOCAL_DELTA; l2Fork = Fork.DELTA;
super.setUp(); super.setUp();
assertEq(gasPriceOracle.isEcotone(), false); assertEq(gasPriceOracle.isEcotone(), false);
...@@ -120,7 +120,7 @@ contract GasPriceOracleBedrock_Test is GasPriceOracle_Test { ...@@ -120,7 +120,7 @@ contract GasPriceOracleBedrock_Test is GasPriceOracle_Test {
contract GasPriceOracleEcotone_Test is GasPriceOracle_Test { contract GasPriceOracleEcotone_Test is GasPriceOracle_Test {
/// @dev Sets up the test suite. /// @dev Sets up the test suite.
function setUp() public virtual override { function setUp() public virtual override {
l2OutputMode = OutputMode.LOCAL_ECOTONE; // activate ecotone l2Fork = Fork.ECOTONE;
super.setUp(); super.setUp();
assertEq(gasPriceOracle.isEcotone(), true); assertEq(gasPriceOracle.isEcotone(), true);
...@@ -213,7 +213,7 @@ contract GasPriceOracleEcotone_Test is GasPriceOracle_Test { ...@@ -213,7 +213,7 @@ contract GasPriceOracleEcotone_Test is GasPriceOracle_Test {
contract GasPriceOracleFjordActive_Test is GasPriceOracle_Test { contract GasPriceOracleFjordActive_Test is GasPriceOracle_Test {
/// @dev Sets up the test suite. /// @dev Sets up the test suite.
function setUp() public virtual override { function setUp() public virtual override {
l2OutputMode = OutputMode.LOCAL_LATEST; // activate fjord l2Fork = Fork.FJORD;
super.setUp(); super.setUp();
bytes memory calldataPacked = Encoding.encodeSetL1BlockValuesEcotone( bytes memory calldataPacked = Encoding.encodeSetL1BlockValuesEcotone(
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { L2Genesis, OutputMode, L1Dependencies } from "scripts/L2Genesis.s.sol"; import { L2Genesis, L1Dependencies } from "scripts/L2Genesis.s.sol";
import { Predeploys } from "src/libraries/Predeploys.sol"; import { Predeploys } from "src/libraries/Predeploys.sol";
import { Constants } from "src/libraries/Constants.sol"; import { Constants } from "src/libraries/Constants.sol";
import { Process } from "scripts/libraries/Process.sol"; import { Process } from "scripts/libraries/Process.sol";
...@@ -181,7 +181,7 @@ contract L2GenesisTest is Test { ...@@ -181,7 +181,7 @@ contract L2GenesisTest is Test {
/// @notice Tests the number of accounts in the genesis setup /// @notice Tests the number of accounts in the genesis setup
function _test_allocs_size(string memory _path) internal { function _test_allocs_size(string memory _path) internal {
genesis.cfg().setFundDevAccounts(false); genesis.cfg().setFundDevAccounts(false);
genesis.runWithOptions(OutputMode.LOCAL_LATEST, _dummyL1Deps()); genesis.runWithLatestLocal(_dummyL1Deps());
genesis.writeGenesisAllocs(_path); genesis.writeGenesisAllocs(_path);
uint256 expected = 0; uint256 expected = 0;
......
...@@ -25,8 +25,10 @@ import { DelayedWETH } from "src/dispute/weth/DelayedWETH.sol"; ...@@ -25,8 +25,10 @@ import { DelayedWETH } from "src/dispute/weth/DelayedWETH.sol";
import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol"; import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol";
import { L1CrossDomainMessenger } from "src/L1/L1CrossDomainMessenger.sol"; import { L1CrossDomainMessenger } from "src/L1/L1CrossDomainMessenger.sol";
import { DeployConfig } from "scripts/DeployConfig.s.sol"; import { DeployConfig } from "scripts/DeployConfig.s.sol";
import { Fork, LATEST_FORK } from "scripts/Config.sol";
import { Deploy } from "scripts/Deploy.s.sol"; import { Deploy } from "scripts/Deploy.s.sol";
import { L2Genesis, L1Dependencies, OutputMode } from "scripts/L2Genesis.s.sol"; import { L2Genesis, L1Dependencies } from "scripts/L2Genesis.s.sol";
import { OutputMode, Fork, ForkUtils } from "scripts/Config.sol";
import { L2OutputOracle } from "src/L1/L2OutputOracle.sol"; import { L2OutputOracle } from "src/L1/L2OutputOracle.sol";
import { ProtocolVersions } from "src/L1/ProtocolVersions.sol"; import { ProtocolVersions } from "src/L1/ProtocolVersions.sol";
import { SystemConfig } from "src/L1/SystemConfig.sol"; import { SystemConfig } from "src/L1/SystemConfig.sol";
...@@ -46,6 +48,8 @@ import { WETH } from "src/L2/WETH.sol"; ...@@ -46,6 +48,8 @@ import { WETH } from "src/L2/WETH.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 {
using ForkUtils for Fork;
/// @notice The address of the foundry Vm contract. /// @notice The address of the foundry Vm contract.
Vm private constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); Vm private constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
...@@ -57,7 +61,7 @@ contract Setup { ...@@ -57,7 +61,7 @@ contract Setup {
L2Genesis(address(uint160(uint256(keccak256(abi.encode("optimism.l2genesis")))))); L2Genesis(address(uint160(uint256(keccak256(abi.encode("optimism.l2genesis"))))));
// @notice Allows users of Setup to override what L2 genesis is being created. // @notice Allows users of Setup to override what L2 genesis is being created.
OutputMode l2OutputMode = OutputMode.LOCAL_LATEST; Fork l2Fork = LATEST_FORK;
OptimismPortal optimismPortal; OptimismPortal optimismPortal;
OptimismPortal2 optimismPortal2; OptimismPortal2 optimismPortal2;
...@@ -175,9 +179,10 @@ contract Setup { ...@@ -175,9 +179,10 @@ 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() public { function L2() public {
console.log("Setup: creating L2 genesis, with output mode %d", uint256(l2OutputMode)); console.log("Setup: creating L2 genesis with fork %s", l2Fork.toString());
l2Genesis.runWithOptions( l2Genesis.runWithOptions(
l2OutputMode, OutputMode.NONE,
l2Fork,
L1Dependencies({ L1Dependencies({
l1CrossDomainMessengerProxy: payable(address(l1CrossDomainMessenger)), l1CrossDomainMessengerProxy: payable(address(l1CrossDomainMessenger)),
l1StandardBridgeProxy: payable(address(l1StandardBridge)), l1StandardBridgeProxy: payable(address(l1StandardBridge)),
......
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