The Cancun upgrade is coming soon. What are the key points to pay attention to and the potential risks?
Written by: Salus Insights
To make a long story short: The Cancun upgrade is approaching, and this upgrade mainly includes six EIPs proposing changes to the execution layer: EIP-1153, EIP-4788, EIP-4844, EIP-5656, EIP-6780, and EIP-7516. EIP-4844 is the star of this upgrade, aimed at enhancing Ethereum's scalability, reducing transaction costs, and increasing transaction speeds for L2. The Cancun upgrade has been completed on the Ethereum Goerli, Sepolia, and Holesky testnets on January 17, January 30, and February 7, respectively, and is scheduled to activate on the Ethereum mainnet on March 13. Before the upgrade, Salus has compiled important security considerations for this upgrade for developers to review.
EIP Proposal Review
EIP-1153
EIP-1153 introduces temporary storage opcodes, which are used to manipulate state and behave almost like storage, but the temporary storage will be discarded at the end of each transaction. This means that temporary storage does not deserialize values from storage or serialize values to storage, thus incurring lower costs due to the lack of disk access. Through two new opcodes, TLOAD and TSTORE (where "T" stands for "temporary"), smart contracts can access temporary storage. This proposal aims to provide a dedicated and efficient solution for communication between multiple nested execution frameworks in Ethereum's transaction execution.
EIP-4788
EIP-4788 aims to expose the hash tree roots of beacon chain blocks to the EVM, allowing access to these roots within smart contracts. This enables trustless access to the consensus layer state, supporting various use cases such as staking pools, restaking structures, smart contract bridges, and MEV mitigation. The proposal stores these roots through a smart contract and uses a circular buffer to limit storage consumption, ensuring that each execution block only requires constant space to represent this information.
EIP-4844
EIP-4844 introduces a new transaction format called "shard blob transactions," aimed at expanding Ethereum's data availability in a simple and forward-compatible manner. This proposal introduces "blob-carrying transactions" that contain a large amount of data that cannot be accessed by EVM execution but can be accessed through its commitments. This format is fully compatible with the format to be used for full sharding in the future, providing temporary but significant relief for rollup scalability.
EIP-5656
EIP-5656 introduces a new EVM instruction, MCOPY, for efficiently copying memory regions. This proposal aims to reduce the overhead of executing memory copy operations on the EVM by directly implementing data copying between memory using the MCOPY instruction. MCOPY allows source and destination addresses to overlap, designed with backward compatibility in mind, and aims to enhance execution efficiency in various scenarios, including data structure construction and efficient access and copying of memory objects.
EIP-6780
EIP-6780 modifies the functionality of the SELFDESTRUCT opcode. In this proposal, SELFDESTRUCT will only delete accounts and transfer all Ether in the same transaction that created the contract. Otherwise, when executing SELFDESTRUCT, the contract will not be deleted but will simply transfer all Ether to the specified target. This change is intended to accommodate the future use of Verkle trees, aiming to simplify EVM implementation, reduce the complexity of state changes, while retaining some common scenarios for SELFDESTRUCT.
EIP-7516
EIP-7516 introduces a new EVM instruction, BLOBBASEFEE, to return the blob base fee value during the execution of the current block. This instruction is similar to the BASEFEE opcode in EIP-3198, with the difference being that it returns the blob base fee defined by EIP-4844. This functionality allows contracts to programmatically consider the gas price of blob data, for example, enabling rollup contracts to calculate blob data usage costs trustlessly or implementing blob gas futures based on this to smooth blob data costs.
Official Security Considerations
EIP-1153
Smart contract developers should understand the lifecycle of transient storage variables before use. Since temporary storage is automatically cleared at the end of a transaction, smart contract developers may attempt to avoid clearing slots during calls to save gas. However, this may prevent further interaction with the contract within the same transaction (e.g., in the case of reentrancy locks) or lead to other errors. Therefore, smart contract developers should be cautious and only retain non-zero values in transient storage slots intended for future calls within the same transaction. Otherwise, the behavior of these opcodes is identical to SLOAD, so all common security considerations apply, especially regarding reentrancy risks.
Smart contract developers may also attempt to use transient storage as an alternative to memory mapping. They should be aware that transient storage does not get discarded like memory when a call returns or reverts, and memory should be prioritized in these use cases to avoid unexpected behavior during reentrancy within the same transaction. The costs of transient storage in memory are necessarily high, which should have already prevented this usage pattern. Most uses of memory mapping can be better implemented with a sorted list of keyed entries, and there is rarely a need for memory mapping in smart contracts (i.e., the author knows there are no known use cases in production).
EIP-4844
This EIP increases the bandwidth requirement for each beacon block by approximately 0.75 MB at most. This is 40% larger than the theoretical maximum size of today's blocks (30M Gas / 16 Gas per calldata byte = 1.875M bytes), so it does not significantly increase the worst-case bandwidth. After merging, block times are static rather than unpredictably Poisson-distributed, providing guaranteed time slots for the propagation of large blocks.
Even with limited call data, the sustained load of this EIP is much lower than alternatives that could reduce call data costs, as there is no need to store blobs for as long as the execution load. This makes it possible to implement strategies that require these blobs to be retained for at least some time. The specific value chosen is MINEPOCHSFORBLOBSIDECARS_REQUESTS epochs, approximately 18 days, which is much shorter than the proposed (but not yet implemented) one-year rotation time for execution payload history.
EIP-5656
Clients should ensure that their implementations do not use intermediate buffers (e.g., C stdlib memmove function does not use intermediate buffers), as this is a potential denial-of-service (DoS) vector. Most built-in functions/standard library functions for moving bytes in languages here have the correct performance characteristics.
In addition, the analysis of denial-of-service (DoS) and memory exhaustion attacks is the same as for other opcodes that touch memory, as memory expansion follows the same pricing rules.
EIP-6780
The following applications of SELFDESTRUCT will be broken, and applications using it in this way will no longer be secure:
Where CREATE2 is used to redeploy contracts at the same location to make contracts upgradeable. This functionality is no longer supported and should be replaced with ERC-2535 or other types of proxy contracts.
If a contract relies on burning Ether by using SELFDESTRUCT with the contract as the beneficiary, the contract is not created in the same transaction.
Smart Contract Related Risks
EIP-1153
Consider two scenarios using the opcodes TLOAD and TSTORE:
- The called contract uses the opcode.
- The calling contract uses the opcode.
Risk 1:
Compared to traditional SSTORE and SLOAD, the new transient storage primarily changes the storage duration of the data. The data stored by tstore is read through tload, and this data will be released at the end of a transaction execution, rather than being permanently recorded in the contract like sstore. Developers should recognize the characteristics of this opcode when using it to avoid incorrect usage that leads to data not being correctly written to the contract, resulting in losses. Additionally, the data in tstore belongs to private variables, accessible only by the contract itself. If external access to this data is desired, it can only be passed as parameters or temporarily stored in a public storage variable.
Risk 2:
Another potential risk is that if smart contract developers do not correctly manage the lifecycle of transient storage variables, it may lead to data being cleared or incorrectly retained at inappropriate times. If a contract expects to use data stored in transient storage in subsequent calls of the transaction but fails to manage the lifecycle of this data appropriately, it may lead to erroneous sharing or loss of data between different calls, resulting in logical errors or security vulnerabilities. Considering that failure to correctly store data similar to balance or allowance in Token projects will lead to errors in contract logic, causing losses. Or using this opcode when setting the owner address may result in the privileged address not being correctly recorded, thus losing the ability to modify important parameters of the contract.
Consider a smart contract that uses transient storage to temporarily record the transaction price on a cryptocurrency trading platform. The contract updates the price at the completion of each transaction and allows users to query the latest price for a short time. However, if the contract design does not take into account the characteristic that transient storage is automatically cleared at the end of the transaction, then during the time between the end of one transaction and the start of the next, users may receive an incorrect or outdated price. This could not only lead users to make decisions based on incorrect information but could also be maliciously exploited, affecting the platform's reputation and the security of users' assets.
EIP-6780
This proposal changes the behavior of the previous selfdestruct opcode, not destroying the contract but only transferring tokens, and only contracts created in the same transaction as the selfdestruct will be destroyed. The impact of this EIP is relatively large.
Using create2 to redeploy contracts at the same address to make contracts upgradeable is no longer supported and should be replaced with ERC-2535 or other types of proxy contracts. (This may affect the security of on-chain contracts that use create2 to implement upgradeable contracts.)
The SELFDESTRUCT operation in smart contracts allows contracts to be destroyed and the contract balance to be sent to a specified target address. In this case, the contract uses SELFDESTRUCT to destroy Ether and sends the destroyed Ether to the contract. However, this contract can only be a contract created in the same transaction (a contract created by this contract or another contract in the same transaction). Otherwise, it will only transfer Ether without destroying the contract (for example, self-destructing with the beneficiary being the self-destructing contract, which will not result in any change). This will affect all contracts that rely on selfdestruct for withdrawals or other operations.
A gas token like the 1inch CHI Token works by maintaining an offset and always executing CREATE2 or SELFDESTRUCT at this offset. After this update, if the contract at the current offset has not been correctly self-destructed, subsequent CREATE2 will not successfully deploy the contract.
The implementation of this proposal does not lead to direct attacks on contracts but will impair the normal logic of already deployed contracts that rely on the selfdestruct operation (contracts that rely solely on selfdestruct for fund transfers are not affected; if subsequent operations require the selfdestructed contract to be deleted, they are affected), leading to unexpected behavior of contracts, which may pose risks such as contract strikes and loss of funds (for example, contracts that originally used create2 to deploy new contracts at the original address and self-destruct the original contract for upgrades will no longer be able to deploy successfully). In the long run, modifying the functionality of an opcode may bring about centralization issues.
For example, consider an existing vault contract being updated:
- create2 temporary storage contract used to temporarily reserve funds for the vault.
- Self-destruct the vault contract, transferring funds to the temporary contract (only transferring funds without destroying the contract).
- Create a new vault contract at the original address using create2 (fails because the original vault contract has not been destroyed).
- Self-destruct the temporary contract to return funds to the vault (fund loss, the vault contract has not been created).