⚠️ This EIP is not recommended for general use or implementation as it is likely to change.

EIP-1153: Transient storage opcodes Source

Add opcodes for manipulating state that behaves identically to storage but is discarded after every transaction

AuthorAlexey Akhunov, Moody Salem
Discussions-Tohttps://ethereum-magicians.org/t/eip-transient-storage-opcodes/553
StatusDraft
TypeStandards Track
CategoryCore
Created2018-06-15

Abstract

This proposal introduces transient storage opcodes, which manipulate state that behaves identically to storage, but is discarded after every transaction. Transient storage is cheaper since it never requires disk access. Transient storage is accessible to smart contracts via 2 new opcodes: TLOAD and TSTORE, where “T” stands for “transient.”

Motivation

Running a transaction in Ethereum can generate multiple nested frames of execution, each created by CALL (or similar) instructions. Contracts can be re-entered during the same transaction, in which case there are more than one frame belonging to one contract. Currently, these frames can communicate in two ways - via inputs/outputs passed via CALL instructions, and via storage updates. If there is an intermediate frame belonging to another untrusted contract, communication via inputs/outputs is not secure. Notable example is a reentrancy lock which cannot rely on the intermediate frame to pass through the state of the lock. Communication via storage (SSTORE/SLOAD) is costly. Transient storage is a dedicated and gas efficient solution to the problem of inter frame communication.

Storage refunds accumulated due to inter frame communication are also limited to 20% of gas spent by a transaction as of EIP-3529 included in the London hard fork. This greatly reduces the refunds for transiently-set storage slots in otherwise low-cost transactions. For example: in order to receive the full refund of one re-entrancy lock, the transaction must spend ~80k gas on other operations.

Language support could be added in relatively easy way. For example, in Solidity, a qualifier “transient” can be introduced (similar to the existing qualifiers “memory” and “storage”, and Java’s own transient keyword with a similar meaning). Since the addressing scheme of TSTORE and TLOAD is the same as for SSTORE and SLOAD, code generation routines that exist for storage variables, can be easily generalised to also support transient storage.

Potential use cases enabled or improved by this EIP include:

  1. Reentrancy lock
  2. Constructor arguments loaded from the factory contract (for on-chain-computable CREATE2 addresses as in Uniswap V3)
  3. Single transaction ERC20 approvals, e.g. #approveAndCall(address callee, uint256 amount, bytes memory data)
  4. Passing error codes and messages from the execution frames up the execution stack
  5. More generic libraries that use callbacks, for example generalised sorting with functions Less and Swap defined.
  6. Contracts that require control before and after method execution (e.g. via callbacks)
  7. Shared memory (borrowed from early draft of similar EIP by @holiman). When implementing contract-proxies using DELEGATECALL, all direct arguments are relayed from the caller to the callee via the CALLDATA, leaving no room for meta-data between the proxy and the proxee. Also, the proxy must be careful about storage access to avoid collision with target storage-slots. Since transient storage would be shared, it would be possible to use transient storage to pass information between the proxy and the target.

These opcodes are more efficient to execute than the SSTORE and SLOAD opcodes because the original value never needs to be loaded from storage (i.e. is always 0). The gas accounting rules are also simpler, and do not involve refunds.

Specification

Two new opcodes are added to EVM, TLOAD and TSTORE.

They use the same arguments on stack as SLOAD (0x54) and SSTORE (0x55).

TLOAD pops one 32-byte word from the top of the stack, treats this value as the address, fetches 32-byte word from the transient storage at that address, and pops the value on top of the stack.

TSTORE pops two 32-byte words from the top of the stack. The word on the top is the address, and the next is the value. TSTORE saves the value at the given address in the transient storage.

Addressing is the same as SLOAD and SSTORE. i.e. each 32-byte address points to a unique 32-byte word.

Gas cost for TSTORE is the same as a hot dirty SSTORE (original value is not new value and is not current value, currently 100 gas), and gas cost of TLOAD is the same as a hot SLOAD (value has been read before, currently 100 gas). Gas cost cannot be on par with memory access due to transient storage’s interactions with reverts.

All values in transient storage are discarded at the end of the transaction.

Transient storage is private to the contract that owns it, in the same way as persistent storage. Only owning contract frames may access their transient storage. And when they do, all the frames access the same transient store, in the same way as persistent storage, but unlike memory.

When transient storage is used in the context of DELEGATECALL or CALLCODE, then the owning contract of the transient storage is the contract that issued DELEGATECALL or CALLCODE instruction (the caller) as with persistent storage. When transient storage is used in the context of CALL or STATICCALL, then the owning contract of the transient storage is the contract that is the target of the CALL or STATICCALL instruction (the callee).

If a frame reverts, all writes to transient storage within that frame are also reverted, as with persistent storage.

Rationale

Another option to solve the problem of inter-frame communication is repricing the SSTORE and SLOAD opcodes to be cheaper for the transient storage use case. This has already been done as of EIP-2200. However, EIP-3529 reduced the maximum refund to only 20% of the transaction gas cost, which means this use case is severely limited.

Another approach is to keep the refund counter for transient storage separate from the refund counter for other storage uses, and remove the refund cap for transient storage. However, that approach is more complex to implement and understand. For example, the 20% refund cap must be applied to the gas used after subtracting the uncapped gas refund. Otherwise, the refund amount available subject to the 20% refund cap could be increased by making a few transient storage writes. Thus it is preferable to have a separate mechanism that does not interact with the refund counter. Future hard forks can remove the complex refund behavior meant to support the transient storage use case, encouraging migration to contracts that are more efficient for clients to execute.

Relative cons of this transient storage EIP:

  • Does not address transient usages of storage in existing contracts
  • New code in the clients
  • New concept for the yellow paper (more to update)

Relative pros of this transient storage EIP:

  • Transient storage opcodes are considered separately in protocol upgrades and not inadvertently broken (e.g. EIP-3529)
  • Clients do not need to load the original value
  • No upfront gas cost to account for non-transient writes
  • Does not change the semantics of the existing operations
  • No need to clear storage slots after usage
  • Simpler gas accounting rules

Backwards Compatibility

This EIP requires a hard fork to implement.

Since this EIP does not change semantics of any existing opcodes, it does not pose risk of backwards incompatibility for existing deployed contracts.

Test Cases

TBD

Reference Implementation

Because the transient storage must behave identically to storage within the context of a single transaction with regards to revert behavior, it is necessary to be able to revert to a previous state of transient storage within a transaction.

A stack of maps is one possible implementation:

  • When a call frame is entered, a new empty map is pushed onto the stack in constant time
  • All transient storage writes are written to the map at the top of the stack in constant time
  • When a call reverts, the map at the top of the stack is popped and discarded in constant time
  • When a call frame exits successfully, the map at the top of the stack is popped and merged with the map now at the top of the stack in linear time with the number of keys written in that call frame

Security Considerations

There are no security considerations for existing contracts not containing the new TSTORE or TLOAD opcodes.

New contracts that use the TSTORE and TLOAD opcodes operate under all the same assumptions as with storage. This EIP introduces no additional mental overhead for the developer. In some cases, transient storage simplifies contracts in that contract transient storage does not need to be cleared at the end of every transaction, e.g. in the temporary approvals use case.

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Alexey Akhunov, Moody Salem, "EIP-1153: Transient storage opcodes [DRAFT]," Ethereum Improvement Proposals, no. 1153, June 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1153.