EIP-3541 Ban deploying new code that starts with 0xEF (Reject new contract code starting with the 0xEF byte)
Final · EVM & execution · EIP status Final · created 2021-03-16
Blocks new deployment of contract code whose first byte is 0xEF. Code that is already deployed keeps its meaning and stays as it is.
Why it is needed
Until now, Ethereum has stored contract code as is at deployment without checking its format. The core of the EVM Object Format (EOF), the new code format planned for introduction, is validating at deployment time that the code is well formed. For that guarantee to hold, previously deployed old code, which was never validated, must not be mistaken for the new format by accident. So a byte value that no existing contract uses must be chosen as the format marker (magic), but as new code of that kind is deployed over time, the values available to choose shrink. This proposal blocks deployment of code starting with 0xEF, the first byte chosen for the magic, now, so that the range to check does not grow further and the analysis is limited to contracts that existed before this fork.
What changes
Today
- A contract can be deployed with code that starts with any byte value
- Deployed code is stored in state without any validation
- Introducing a new code format leaves no safe marker to tell it apart from old code
After EIP-3541
- Deployment fails for code whose first byte is 0xEF
- 0xEF-prefixed code that is already deployed stays in place and its behavior does not change
- 0xEF is reserved as the marker that identifies a new code format
Who is affected
- Ordinary users: There is no noticeable change. Code starting with 0xEF cannot be executed today anyway.
- Contract developer: Even a contract that stores data and is never executed as code cannot be deployed if its first byte is 0xEF.
- Client teams: A check on the first byte of the code must be added to create transaction handling and to CREATE and CREATE2 processing.
- EOF designers: This gives a basis for guaranteeing that every EOF-format code in state has passed validation.
In depth
Rule: rejected on all three creation paths
From block HF_BLOCK onward, when a new contract is created, if the first byte of the code to be placed in the account is 0xEF, creation fails with an exceptional abort. All three creation paths are covered: the create transaction, the CREATE instruction, and the CREATE2 instruction. The check applies to the code returned by the initcode through RETURN, not to the initcode itself. This exceptional abort behaves the same as any other exceptional abort during initcode execution, so all gas provided to CREATE* or the create transaction is consumed.
Existing code and initcode are unaffected
0xEF is currently an undefined instruction. When executed, it pops nothing from the stack and pushes nothing, and it causes an exceptional abort. Therefore initcode or already deployed code that starts with 0xEF aborts on execution both before and after this proposal, and its meaning does not change. 0xEF-prefixed code that already exists in the account trie also stays as it is. The only thing that changes is that such code can no longer be newly deployed.
Why 0xEF
0xEF was chosen because the value evokes Executable Format. It is generally understood that a contract using an unassigned instruction risks a change in meaning, so using the unassigned 0xEF has less impact than picking an already assigned instruction such as 0xFD (REVERT), 0xFE (INVALID), or 0xFF (SELFDESTRUCT). An analysis of 18,084,433 contracts in state as of May 2021 found 0 contracts starting with 0xEF, while 1, 4, and 12 contracts started with 0xFD, 0xFE, and 0xFF respectively.
Test cases
Each test runs in three contexts: a create transaction with no account code, account code that uses CREATE, and account code that uses CREATE2. Deploying one byte ef, two bytes ef00, three bytes ef0000, or 32 bytes ef00...00 all result in no new contract being deployed and the transaction failing. By contrast, deploying one byte fe deploys the contract and the transaction succeeds. In other words, the only rejection criterion is whether the first byte is 0xEF. The length and the rest of the content are not examined.
Compatibility: only data contracts break
Because new code starting with 0xEF can no longer be deployed, this is formally a backward-incompatible change. However, bytecode executes from its first byte, so code starting with 0xEF cannot be executed anyway, and none of the currently executable contracts are affected. The change does affect contracts that are deployed to store data without being executed and that start with 0xEF; such deployments can no longer be made. The authors state that they are not aware of any security or denial-of-service (DoS) risk caused by this change.
Easy to revert if EOF falls through
Even if the EVM Object Format proposal is never deployed, the reserved magic can be used by other features that depend on versioning. If versioning itself becomes unnecessary, the change can be reverted simply by allowing deployment of code starting with 0xEF again. This EIP was finalized with Final status and has been applied to Ethereum.