-
Notifications
You must be signed in to change notification settings - Fork 202
specs: add L2 contract upgrades overview and ConditionalDeployer #876
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| # L2 Contract Upgrades | ||
|
|
||
| <!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
| <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
| **Table of Contents** | ||
|
|
||
| - [Overview](#overview) | ||
| - [ConditionalDeployer](#conditionaldeployer) | ||
| - [Overview](#overview-1) | ||
| - [Definitions](#definitions) | ||
| - [CREATE2 Collision](#create2-collision) | ||
| - [Deterministic Deployment Proxy](#deterministic-deployment-proxy) | ||
| - [Assumptions](#assumptions) | ||
| - [a01-001: Deterministic Deployment Proxy is Available and Correct](#a01-001-deterministic-deployment-proxy-is-available-and-correct) | ||
| - [Mitigations](#mitigations) | ||
| - [a02-002: Initcode is Well-Formed](#a02-002-initcode-is-well-formed) | ||
| - [Mitigations](#mitigations-1) | ||
| - [Invariants](#invariants) | ||
| - [i01-001: Deterministic Address Derivation](#i01-001-deterministic-address-derivation) | ||
| - [Impact](#impact) | ||
| - [i02-002: Idempotent Deployment Operations](#i02-002-idempotent-deployment-operations) | ||
| - [Impact](#impact-1) | ||
| - [i03-003: Non-Reverting Collision Handling](#i03-003-non-reverting-collision-handling) | ||
| - [Impact](#impact-2) | ||
| - [i04-004: Collision Detection Accuracy](#i04-004-collision-detection-accuracy) | ||
| - [Impact](#impact-3) | ||
|
|
||
| <!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
|
|
||
| ## Overview | ||
|
|
||
| This specification defines the mechanism for upgrading L2 predeploy contracts through deterministic, hard fork-driven | ||
| Network Upgrade Transactions (NUTs). The system enables safe, well-tested upgrades of L2 contracts with both | ||
| implementation and upgrade paths written in Solidity, ensuring determinism, verifiability, and testability across all | ||
| client implementations. | ||
|
|
||
| The upgrade system maintains the existing pattern of injecting Network Upgrade Transactions at specific fork block | ||
| heights while improving the development and testing process. Upgrade transactions are defined in JSON bundles that are | ||
| tracked in git, generated from Solidity scripts, and executed deterministically at fork activation. | ||
|
|
||
| ## ConditionalDeployer | ||
|
|
||
| ### Overview | ||
|
|
||
| The ConditionalDeployer contract enables deterministic deployment of contract implementations while maintaining | ||
| idempotency across upgrade transactions. It ensures that unchanged contract bytecode always deploys to the same | ||
| address, and that attempting to deploy already-deployed bytecode succeeds silently _rather than reverting_. | ||
|
|
||
| This component enables upgrade transactions to unconditionally deploy for all implementation contracts without | ||
| requiring developers to manually track which contracts have changed between upgrades. | ||
|
|
||
| ### Definitions | ||
|
|
||
| #### CREATE2 Collision | ||
|
|
||
| A CREATE2 collision occurs when attempting to deploy contract bytecode to an address where a contract with identical | ||
| bytecode already exists. This happens when the same initcode and salt are used in multiple deployment attempts. | ||
|
|
||
| Note: when CREATE2 targets an address that already has code, the | ||
| [zero address is placed on the stack][create2-spec] (execution specs). | ||
|
|
||
| [create2-spec]: | ||
| https://github.com/ethereum/execution-specs/blob/4ef381a0f75c96b52da635653ab580e731d3882a/src/ethereum/forks/prague/vm/instructions/system.py#L112 | ||
|
|
||
| #### Deterministic Deployment Proxy | ||
|
|
||
| The canonical deterministic deployment proxy contract at address `0x4e59b44847b379578588920cA78FbF26c0B4956C`, | ||
| originally deployed by Nick Johnson (Arachnid). This contract provides CREATE2-based deployment with a fixed deployer | ||
| address across all chains. | ||
|
|
||
| Note: when the deterministic deployment proxy deploys to an address that already has code, [it will revert with no data](https://github.com/Arachnid/deterministic-deployment-proxy/blob/be3c5974db5028d502537209329ff2e730ed336c/source/deterministic-deployment-proxy.yul#L13). | ||
| Otherwise the ConditionalDeployer would not be required. | ||
|
|
||
| ### Assumptions | ||
|
|
||
| #### a01-001: Deterministic Deployment Proxy is Available and Correct | ||
|
|
||
| The [Deterministic Deployment Proxy](#deterministic-deployment-proxy) exists at the expected address and correctly | ||
| implements CREATE2 deployment semantics. The proxy must deterministically compute deployment addresses and execute | ||
| deployments as specified. | ||
|
|
||
| ##### Mitigations | ||
|
|
||
| - The [Deterministic Deployment Proxy](#deterministic-deployment-proxy) is a well-established contract deployed across | ||
| all EVM chains using the same keyless deployment transaction | ||
| - The proxy's behavior is verifiable by inspecting its bytecode and testing deployment operations | ||
| - The proxy contract is immutable and cannot be upgraded or modified | ||
|
|
||
| #### a02-002: Initcode is Well-Formed | ||
|
|
||
| Callers provide valid EVM initcode that, when executed, will either successfully deploy a contract or revert with a | ||
| clear error. Malformed initcode that produces undefined behavior is not considered. | ||
|
|
||
| ##### Mitigations | ||
|
|
||
| - Initcode is generated by the Solidity compiler from verified source code | ||
| - The upgrade transaction generation process includes validation of all deployment operations | ||
| - Fork-based testing exercises all deployments before inclusion in upgrade bundles | ||
|
|
||
| ### Invariants | ||
|
|
||
| #### i01-001: Deterministic Address Derivation | ||
|
|
||
| For any given initcode and salt combination, the ConditionalDeployer MUST always compute the same deployment address, | ||
| regardless of whether the contract has been previously deployed. The address calculation MUST match the CREATE2 | ||
| address that would be computed by the [Deterministic Deployment Proxy](#deterministic-deployment-proxy). | ||
|
|
||
| ##### Impact | ||
|
|
||
| **Severity: Critical** | ||
|
|
||
| If address derivation is non-deterministic or inconsistent with CREATE2 semantics, upgrade transactions could deploy | ||
| implementations to unexpected addresses. This would break proxy upgrade operations that expect implementations at | ||
| specific predetermined addresses, potentially causing proxies to point to non-existent or incorrect implementations. | ||
|
|
||
| #### i02-002: Idempotent Deployment Operations | ||
|
|
||
| Calling the ConditionalDeployer multiple times with identical initcode and salt MUST produce the same outcome: the | ||
| first call deploys the contract, and subsequent calls succeed without modification. No operation should revert due to | ||
| a [CREATE2 Collision](#create2-collision). | ||
|
|
||
| ##### Impact | ||
|
|
||
| **Severity: Critical** | ||
|
|
||
| If deployments are not idempotent, upgrade transactions that attempt to deploy unchanged implementations would revert | ||
| or deploy the implementation to an unexpected address. In the latter case, the proxy would then be upgrade incorrectly, | ||
| as we must predict the implementation address in advance in order to correctly generate the NUT bundle. | ||
|
|
||
| #### i03-003: Non-Reverting Collision Handling | ||
|
|
||
| When a [CREATE2 Collision](#create2-collision) is detected (contract already deployed at the target address), the | ||
| ConditionalDeployer MUST return successfully without reverting and without modifying blockchain state. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe worth mentioning what address it will return in case of collision
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think it should return the deployment address? In some ways it doesn't matter since we can't actually use the return value, as it needs to be pre-computed off-chain (all we can do is inject transactions, we can't read their results).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the cleaner approach would be to just not return anything, as you mention for this use case we cannot use the address anyway and returning the address in cases where no contract is deployed (because it was deployed before) feels off. |
||
|
|
||
| ##### Impact | ||
|
|
||
| **Severity: Medium** | ||
|
|
||
| If the collisions cause reverts, the following transactions can still proceed, however the presence of reverting | ||
| transactions in an upgrade block is likely to lead to confusion. | ||
|
|
||
| #### i04-004: Collision Detection Accuracy | ||
|
|
||
| The ConditionalDeployer MUST correctly distinguish between addresses where no contract exists (deploy needed) and | ||
| addresses where a contract already exists (collision detected). False negatives (failing to detect existing contracts) | ||
| and false positives (detecting non-existent contracts) are both prohibited. | ||
|
|
||
| ##### Impact | ||
|
|
||
| **Severity: High** | ||
|
|
||
| False negatives would cause the ConditionalDeployer to attempt redeployment to occupied addresses, resulting in | ||
| failed deployments and breaking the upgrade process. False positives would prevent legitimate deployments from | ||
| occurring, causing proxies to reference non-existent implementation addresses. | ||
|
|
||
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.
ConditionDeployeris gonna be a periphery contract rather than a Predeploy right?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.
What do you mean by periphery contract, like a pre-install?
My thoughts: