AlertSourceDiscuss
Skip to content

EIP-6913: SETCODE instruction

replace code in-place

⚠️ DraftCore

Draft Notice

This EIP is in the process of being drafted. The content of this EIP is not final and can change at any time; this EIP is not yet suitable for use in production. Thank you!

AuthorsWilliam Morriss (@wjmelements)
Created2023-04-20

Abstract

Introduce the SETCODE (0xfc) instruction, which replaces the code of the executing account from memory.

Motivation

Many contracts are upgradeable in order to facilitate improvement or defer decisions without migrating to a new address. Contracts presently do this in several ways:

The oldest method uses CALL. The limitation of this method is that internal state must be modifiable by all future implementations.

Second, DELEGATECALL can proxy the implementation. Some proxies are minimal while others branch to many separate implementation accounts. This method can also bypass account code size limits.

A third method uses SELFDESTRUCT and CREATE2 to replace code in-place. This method improves upon the prior methods by removing the need to call into external contracts. One limitation of this method is that any internal state is removed by SELFDESTRUCT. Another limitation is that SELFDESTRUCT does not remove code until the end of the transaction, sacrificing availability until CREATE2 can complete the upgrade.

Given the upcoming deprecation of SELFDESTRUCT, SETCODE introduces a better method for replacing code in-place.

Specification

When within a read-only execution scope like the recursive kind created by STATICCALL, SETCODE causes an exceptional abort. When inside of a CREATE-like execution scope that returns new code for the executing address (the account returned by ADDRESS), SETCODE causes an exceptional abort. When inside of a DELEGATECALL-like execution scope where the currently executing code does not belong to the executing account, SETCODE causes an exceptional abort.

Otherwise, SETCODE consumes two words from the stack: offset and length. These specify a range of memory containing the new code. Any validations that would be performed on the result of CREATE or CREATE2 occur immediately, potentially causing failure with exceptional abort. The operations EXTCODESIZE and EXTCODECOPY now query the updated code, and message-calls such as DELEGATECALL, CALLCODE, CALL, and STATICCALL now execute the updated code. Any execution scopes already executing replaced code, including the one that SETCODE, will continue executing the prior code. Inside such scopes, CODESIZE and CODECOPY continue to query the executing code.

Like SSTORE, this account modification will be reverted if the current scope or any parent scope reverts or aborts.

Unlike SELFDESTRUCT, SETCODE does not clear account balance, nonce, or storage.

Gas

The gas cost of this operation is the sum of Gselfdestruct and the product of Gcodedeposit and the number of bytes in the new code.

Rationale

The behavior of CODECOPY, CODESIZE, EXTCODESIZE, and EXTCODECOPY match the behavior of DELEGATECALL and CREATE, where it is also possible for executing code to differ from the code of the executing account.

The gas cost of SETCODE is comparable to CREATE but excludes Gcreate because no execution context is created, nor any new account. Other account modification costs are accounted for outside of execution gas.

Unlike SELFDESTRUCT, execution proceeds normally after SETCODE in order to allow validation and return data. Post-update validation can undo a SETCODE operation with REVERT or with a subesequent SETCODE, but REVERT uses less-gas.

Preventing SETCODE within DELEGATECALL allows static analysis to easily identify mutable code. Account code not containing the SETCODE operation can be safely assumed to be immutable.

Backwards Compatibility

The only prior operation changing code is SELFDESTRUCT. As code modification via SELFDESTRUCT is deferred until the end of the transaction, its interactions with SETCODE are well-defined.

Test Cases

CodeStartCallDataCodeResultGas
365f5f37365ffc00365f5f37365ffc00365f5f37365ffc006613
365f5f37365ffc0000005213
365f5f37365ffc005013
365f5f37365ffc595ffd365f5f37365ffc00365f5f37365ffc595ffd6617
365f5f37365ffcfe365f5f37365ffc00365f5f37365ffcfeall

Security Considerations

Risks related to SETCODE similarly apply to other upgrade patterns.

Most contracts should never be replaced and should not be upgradeable. Any upgrade mechanism can risk permanent failure. The possibility of upgrade perpetuates such risk.

Access to upgrade operations should be restricted. Upgrades should never be performed in a hurry or when tired. Upgrades should be tested under as similar conditions to production as possible; discrepancies are sources of unexpected results. When possible, multiple engineers should preview and independently verify pending upgrade procedures.

Block explorers, wallets, and other interfaces should flag upgradeable code. Client software should warn against approving ERC-20 or ERC-721 tokens for upgradeable accounts.

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

William Morriss, "EIP-6913: SETCODE instruction[DRAFT]," Ethereum Improvement Proposals, no. 6913, 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6913.