-
Notifications
You must be signed in to change notification settings - Fork 23
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
OP Stack Manager architecture to support interop #60
Merged
Merged
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,294 @@ | ||
# Purpose | ||
|
||
OP Stack Manager is a contract that will deploy the L1 contracts for standard OP Stack chains in a single transaction. | ||
However, we also have use cases for deploying non-standard chains, such as deploying devnet and testnet contracts while developing interop. | ||
This document will outline an architecture that: | ||
|
||
- Enables the OP Stack Manager to deploy these non-standard chains as an initial milestone. | ||
- Gets us most of the way towards supporting standard chains deployments for the subsequent milestone. | ||
|
||
# Summary | ||
|
||
The original OP Stack Manager (OPSM) milestones were: | ||
|
||
- Milestone 1: Eliminating key handover complexity. | ||
- Milestone 2: Simplifying Superchain upgrades. | ||
- Milestone 3: Supporting interop upgrades. | ||
|
||
This design doc proposes the architecture for a Milestone 0.5 of "OPSM is used for all interop devnet & testnet L1 deployments". | ||
Adding this milestone will allow the interop team to build testing infrastructure that wraps OPSM, unifying our development, testnet, and production testing and deployment processes. | ||
|
||
# Problem Statement + Context | ||
|
||
*Some text copied from https://github.com/ethereum-optimism/design-docs/pull/52, which is related to this design doc.* | ||
|
||
The current L2 chain deployment approach originates from a time with Hardhat, single L1 target, and a single monolithic set of features. | ||
Since then the system has migrated to Foundry and extended for more features, but remains centered around a single monolithic deploy-config for all its features. | ||
|
||
The interop team needs a way to configure new multi-L2 deployments: The number of ways to compose L2s in tests grows past what a single legacy config template can support. | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Outside of interop, deployment also seems increasingly complex and opaque, while it does not have to be, due to the same configuration and composability troubles. | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Part of the solution to this is described in [design doc 52](https://github.com/ethereum-optimism/design-docs/pull/52), and the other part involves restructuring our Solidity config processing and deploy scripts. | ||
This design doc focuses on the L1 contract configuration and deployment part of the solution. | ||
|
||
# Alternatives Considered | ||
|
||
The primary alternative is for the interop team to not use OPSM for devnet and testnet deployments. | ||
This is not ideal for various reasons: | ||
|
||
- Duplication of effort: The interop team would need to develop and maintain their own deployment scripts, even though new ones will already be written for OPSM. | ||
- Divergence: With duplication, it's likely the interop team's deployment scripts diverge from the production deployment scripts, leading to inconsistencies and bugs. | ||
|
||
# Proposed Solution | ||
|
||
There are three aspects to deploying L1 contracts: | ||
|
||
1. **Deploy Superchain Contracts**. Superchain contracts are shared between many OP chains, so this occurs only occasionally in production. | ||
2. **Deploy Shared Implementation Contracts**. This occurs once per [contracts release](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/VERSIONING.md). | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
3. **Deploy OP Chain Contracts**. This occurs for every OP chain deployment. | ||
|
||
For each step we define the step inputs (configuration), sub-steps that occur, and the step outputs (artifacts). | ||
For each we start by listing the sub-steps, then define the inputs and outputs for each sub-step, and use those to define the inputs and outputs for the step as a whole. | ||
|
||
Sample input and output TOML files are included for each step. | ||
The exact structure of these files is too low-level to be in-scope for this design doc, so just consider them as examples. | ||
However, feel free to comment on specifics if you think they're important. | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
TOML is used because it is what the superchain-registry is standardizing on, it can be parsed by forge and go, it supports comments (unlike JSON), and it does not have the [quirks](https://noyaml.com/) of YAML. | ||
|
||
Each step is a separate forge script that takes the input TOML file as the only input, and outputs a TOML file. | ||
To make the artifact self-contained, the outputs also include the inputs. | ||
This allows a single artifact to be used to convey all information needed about a deployment. | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
These forge scripts can be wrapped with go code to facilitate e2e testing by the interop team. | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
The go code should leverage the same file-based interface to ensure equivalence between the forge script execution and the go execution. | ||
|
||
## Step 1: Deploy Superchain contracts | ||
|
||
The sub-steps are: | ||
|
||
1. Deploy a `ProxyAdmin`. | ||
2. Deploy a `Proxy` owned by `ProxyAdmin`, set the `SuperchainConfig` contract as its implementation, and initialize it. | ||
3. Deploy a `Proxy` owned by `ProxyAdmin`, set the `ProtocolVersions` contract as its implementation, and initialize it. | ||
|
||
The inputs for each sub-step are: | ||
|
||
1. A `proxyAdminOwner`. | ||
2. The Guardian address and the initial pause status. (The admin of its `Proxy` is always the `ProxyAdmin` from sub-step 1, so this is not an input). | ||
3. A `protocolVersionsOwner`, the `requiredVersion`, and the `recommendedVersion`. (The admin of its `Proxy` is always the `ProxyAdmin` from sub-step 1, so this is not an input). | ||
|
||
The outputs for each sub-step are: | ||
|
||
1. The `superchainProxyAdmin` contract address. | ||
2. The `superchainConfigProxy` and `superchainConfigImplementation` contract addresses. | ||
3. The `protocolVersionsProxy` and `protocolVersionsImplementation` contract addresses. | ||
|
||
A sample TOML deploy config input for this step might look like: | ||
|
||
```toml | ||
[roles] | ||
proxyAdminOwner = "0x1234..." | ||
protocolVersionsOwner = "0x1234..." | ||
|
||
[superchain_config] | ||
guardian = "0x1234..." | ||
paused = false | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
[protocol_versions] | ||
requiredVersion = "0.1.0" | ||
recommendedVersion = "0.1.0" | ||
``` | ||
|
||
A sample TOML output for this step might look like: | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```toml | ||
superchainProxyAdmin = "0x1234..." | ||
superchainConfigProxy = "0x1234..." | ||
superchainConfigImpl = "0x1234..." | ||
protocolVersionsProxy = "0x1234..." | ||
protocolVersionsImpl = "0x1234..." | ||
|
||
# Everything above this comment are the outputs, below are the inputs. | ||
[roles] | ||
proxyAdminOwner = "0x1234..." | ||
protocolVersionsOwner = "0x1234..." | ||
|
||
[superchain_config] | ||
guardian = "0x1234..." | ||
paused = false | ||
|
||
[protocol_versions] | ||
requiredVersion = "0.1.0" | ||
recommendedVersion = "0.1.0" | ||
``` | ||
|
||
## Step 2: Deploy Shared Implementation Contracts | ||
|
||
We assume the latest Fault Proofs release `op-contracts/v1.5.0`. | ||
The exact set of sub-steps and inputs may change with future releases. | ||
|
||
The sub-steps are deploying the following contracts: | ||
|
||
1. DisputeGameFactory | ||
2. AnchorStateRegistry | ||
3. DelayedWETH | ||
4. PreimageOracle | ||
5. MIPS | ||
6. OptimismPortal | ||
7. SystemConfig | ||
8. L1CrossDomainMessenger | ||
9. L1ERC721Bridge | ||
10. L1StandardBridge | ||
11. OptimismMintableERC20Factory | ||
|
||
The inputs for each sub-step are: | ||
|
||
1. None | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. None (takes prior step's address as an input) | ||
1. `withdrawalDelaySeconds` | ||
1. `minProposalSizeBytes` `challengePeriodSeconds` | ||
1. None (takes prior step's address as an input) | ||
1. `_proofMaturityDelaySeconds` `disputeGameFinalityDelaySeconds` | ||
1. None | ||
1. None | ||
1. None | ||
1. None | ||
1. None | ||
|
||
The outputs for each sub-step are the contract addresses of each deploy. | ||
|
||
A sample TOML deploy config input for this step might look like: | ||
|
||
```toml | ||
[fault_proofs] | ||
withdrawalDelaySeconds = 1 | ||
minProposalSizeBytes = 1 | ||
challengePeriodSeconds = 1 | ||
proofMaturityDelaySeconds = 1 | ||
disputeGameFinalityDelaySeconds = 1 | ||
``` | ||
|
||
A sample TOML output for this step might look like: | ||
|
||
```toml | ||
disputeGameFactoryImpl = "0x123..." | ||
anchorStateRegistryImpl = "0x123..." | ||
delayedWETHImpl = "0x123..." | ||
preimageOracleImpl = "0x123..." | ||
mipsImpl = "0x123..." | ||
optimismPortalImpl = "0x123..." | ||
systemConfigImpl = "0x123..." | ||
l1CrossDomainMessengerImpl = "0x123..." | ||
l1ERC721BridgeImpl = "0x123..." | ||
l1StandardBridgeImpl = "0x123..." | ||
optimismMintableERC20FactoryImpl = "0x123..." | ||
|
||
# Everything above this comment are the outputs, below are the inputs. | ||
[fault_proofs] | ||
withdrawalDelaySeconds = 1 | ||
minProposalSizeBytes = 1 | ||
challengePeriodSeconds = 1 | ||
proofMaturityDelaySeconds = 1 | ||
disputeGameFinalityDelaySeconds = 1 | ||
``` | ||
|
||
## Step 3: Deploy OP Chain Contracts | ||
|
||
We assume the latest Fault Proofs release `op-contracts/v1.5.0`. | ||
The exact set of sub-steps and inputs may change with future releases. | ||
|
||
The sub-steps are: | ||
|
||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. Deploy `AddressManager` | ||
2. Deploy `ProxyAdmin` with it's owner set to `address(this)` and call `proxyAdmin.setAddressManager(addressManager)` | ||
3. Deploy `Proxy`s for: | ||
1. `DisputeGameFactory` | ||
2. `AnchorStateRegistry` | ||
3. `DelayedWETH` | ||
4. `PreimageOracle` | ||
5. `MIPS` | ||
6. `L1ERC721Bridge` | ||
7. `OptimismPortal` | ||
8. `SystemConfig` | ||
9. `OptimismMintableERC20Factory` | ||
4. Deploy and configure the legacy proxied contracts and their implementations, `L1StandardBridge` and `L1CrossDomainMessenger`. (Details left out for brevity). | ||
5. Deploy the `FaultDisputeGame` and `PermissionedDisputeGame` contracts. | ||
6. Set and initialize all proxy implementations | ||
7. Transfer ownership of the `ProxyAdmin` to the input `proxyAdminOwner`. | ||
|
||
The L2 chain ID is an input needed to generate the salt for contract deployment. | ||
Other inputs for each sub-step are: | ||
|
||
1. None | ||
2. None | ||
3. None | ||
4. None | ||
5. Various FDG and PDG inputs: Left out for brevity | ||
6. Various contract inputs: | ||
1. Roles: `proxyAdminOwner`, `systemConfigOwner`, `batcher`, `unsafeBlockSigner`, `proposer`, `challenger` | ||
2. Fees: `basefeeScalar`, `blobBaseFeeScalar` | ||
3. Fault Proof inputs: Left out for brevity | ||
7. None | ||
|
||
The outputs from each step are contract addresses. | ||
|
||
A sample TOML deploy config input for this step might look like: | ||
|
||
```toml | ||
l2ChainId = 10 | ||
|
||
[roles] | ||
proxyAdminOwner = "0x123..." | ||
systemConfigOwner = "0x123..." | ||
batcher = "0x123..." | ||
unsafeBlockSigner = "0x123..." | ||
proposer = "0x123..." | ||
challenger = "0x123..." | ||
|
||
[fees] | ||
basefeeScalar = 1 | ||
blobBaseFeeScalar = 1 | ||
|
||
[fault_proofs] | ||
# left out for brevity | ||
``` | ||
|
||
A sample TOML output for this step might look like: | ||
|
||
```toml | ||
systemConfigProxy = "0x123..." | ||
l1ERC721BridgeProxy = "0x123..." | ||
faultDisputeGame = "0x123..." | ||
addressManager = "0x123..." | ||
# etc. | ||
|
||
# Everything above this comment are the outputs, below are the inputs. | ||
l2ChainId = 10 | ||
|
||
[roles] | ||
proxyAdminOwner = "0x123..." | ||
systemConfigOwner = "0x123..." | ||
batcher = "0x123..." | ||
unsafeBlockSigner = "0x123..." | ||
proposer = "0x123..." | ||
challenger = "0x123..." | ||
|
||
[fees] | ||
basefeeScalar = 1 | ||
blobBaseFeeScalar = 1 | ||
|
||
[fault_proofs] | ||
# left out for brevity | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
The initial version of these input files will be minimal and only include the required inputs to deploy standard chains. | ||
Future versions will include more inputs to support more complex deployments, such as custom gas tokens or alt-DA. | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
The deploy scripts and OP Stack Manager code will be written in such a way to default to standard chains and only require additional inputs for non-standard chains. | ||
|
||
# Risks & Uncertainties | ||
mds1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
1. Need to make sure this architecture actually works for the interop team for the goal of deduplicating deploy scripts. | ||
2. Need to verify which fault proof contract inputs should be exposed to users vs. which are "static" or can be inferred from other inputs. | ||
3. It must be sufficiently extensible to handle new features such as supporting the `DataAvailabilityChallenge` contract required for Alt-DA. | ||
4. The exact transition plan from the current legacy `DeployConfig.s.sol` to this new system is not yet defined. We'll likely want a script that can convert legacy deploy configs to the new modular format to ease the transition. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tynes I like this idea, though I'm not sure we can return 100% of the required data, for example the genesis key