EIP-1153 Transient storage opcodes (TLOAD/TSTORE) (Transient storage opcodes)
Final · EVM & execution · EIP status Final · created 2018-06-15
Adds transient storage to the EVM, which automatically disappears when a transaction ends. It is read and written with the new TLOAD and TSTORE opcodes, and is cheaper than persistent storage since it never touches disk.
Why it is needed
A single Ethereum transaction can create multiple layers of execution frames through call instructions like CALL, and the same contract can even be called back into within one transaction. Right now there are only two ways for these frames to exchange information with each other: call input/output and persistent storage. If an untrusted contract sits in between, passing data through input/output is not safe. A classic example is the reentrancy lock. Using persistent storage (SSTORE/SLOAD) is safe but expensive. On top of that, EIP-3529 from the London hard fork capped gas refunds at 20% of the gas used by a transaction, making it hard to get a proper refund for a slot that is written and then cleared shortly after. Fully refunding a single reentrancy lock requires spending roughly 80,000 gas on other work. This EIP solves the inter-frame communication problem cheaply and simply by creating a dedicated transient storage that is discarded entirely once the transaction ends.
What changes
Today
- Passing values between frames requires either expensive persistent storage (SSTORE/SLOAD) or relying on call input/output that passes through untrusted intermediate contracts
- Gas refunds for slots that are briefly written and then cleared are capped at only 20% of the transaction's gas
- Common safeguards like reentrancy locks end up costing more than they should
After EIP-1153
- The TLOAD and TSTORE opcodes read and write storage that persists only for the duration of the transaction, each costing 100 gas
- Values disappear automatically when the transaction ends, so there is no need to clear slots or compute refunds
- Patterns like reentrancy locks, single-transaction ERC-20 approvals, and passing proxy metadata become cheap and safe
Who is affected
- Smart contract developers: Inter-frame communication patterns such as reentrancy locks can be implemented at much lower gas cost. However, developers must understand the difference in lifetime: values do not disappear when a call ends, only when the transaction ends.
- Users: Transaction gas costs fall for apps that use patterns like reentrancy locks or one-time approvals.
- Client teams: Two new opcodes need to be implemented. The original text recommends an implementation that adds a change journal and checkpoints on top of the current state map.
- Language and compiler developers: Since the addressing scheme matches existing storage, support can be added relatively easily, for example by adding a transient qualifier to Solidity.
In depth
The two opcodes and addressing scheme
TLOAD (0x5c) and TSTORE (0x5d) are added. Their stack arguments match SLOAD (0x54) and SSTORE (0x55). TLOAD pops one 32-byte word off the stack as an address, reads the corresponding 32-byte word from transient storage, and pushes it onto the stack. TSTORE pops two words, using the top as the address and the next as the value, and stores it. The addressing scheme is the same as SLOAD/SSTORE: a single 32-byte address points to a unique 32-byte word. Early drafts used 0xb3 and 0xb4 to avoid collisions, but once the collisions were gone the current values were adopted. All values are discarded when the transaction ends.
Gas cost and the stipend exception
TSTORE costs 100 gas, the same as a warm SSTORE on a dirty slot, and TLOAD costs 100 gas, the same as a hot SLOAD. The original text explains that it cannot be lowered to memory-access-level cost due to interactions with revert. TSTORE is also exempt from the gas stipend check defined by EIP-2200 (checking whether remaining gas is 2,300 or less). Since there is no need to read the original value from disk and no refunds apply, the gas accounting rules are simpler than for SSTORE.
Ownership and call context
Like persistent storage, transient storage is only visible to its owning contract. Unlike memory, all frames of the owning contract share the same transient storage. Inside DELEGATECALL or CALLCODE, the owner is the party that executed that instruction (the caller); inside CALL or STATICCALL, the owner is the target of the call (the callee). This mirrors the rule for persistent storage. Executing TSTORE inside a STATICCALL context raises an exception; TLOAD is allowed.
Revert behavior and recommended implementation
If a frame reverts, all transient storage writes that occurred after entering that frame are rolled back, including writes made by inner calls. This matches the behavior of persistent storage. The reference implementation keeps a journal recording every change alongside a list of checkpoints, layered on top of the current state map. Entering a frame, writing, and normal exit are all O(1); only reverting is O(N), proportional to the number of journal entries since the last checkpoint. The original text explains that even in the worst case this is on par with existing clients' state journaling, so this path cannot be used to mount a denial-of-service attack.
Why a new opcode instead of a refund tweak
The path of tweaking SSTORE/SLOAD to be cheaper for temporary use was already taken with EIP-2200, but EIP-3529 exposed its limits by cutting the refund cap to 20%. An alternative of giving temporary-use refunds their own separate counter with no cap was considered, but interactions such as the order in which the cap is applied make it more complex to implement and reason about. So a separate mechanism that does not interact with the refund counter at all was chosen instead. The reason a word-addressed, storage-like interface was chosen over a byte-addressed, memory-like one is mappings: use cases like ERC-20 transient approvals need arbitrary keys such as (owner, spender), and implementing a mapping over linear memory would be difficult, with more complex dynamic gas and revert handling.
Security considerations: memory allocation quota and lifetime
TSTORE is a new, linearly-costed memory allocation mechanism, storing 32 bytes per 100 gas. With 30 million gas, it can accumulate up to about 9.15 MB. MSTORE allows about 3.75 MB within a single context, but since each context gets its own 1 million gas allocation and calls reset the memory expansion cost, a total of up to about 20 MB is possible, so this is not very different from the status quo. Developers should still be careful: skipping slot cleanup at the end of a call to save gas can block or introduce bugs in subsequent calls within the same transaction, and using it as a memory substitute can leave values lingering after a call ends, causing unexpected behavior on reentrancy. Otherwise, the usual precautions that apply to SSTORE/SLOAD, including reentrancy risk, apply here as well.
Compatibility and status
This EIP requires a hard fork to take effect. It does not change the behavior of existing opcodes, so it is fully compatible with all already-deployed smart contracts. Its status is finalized as Final, and its test suite is in the ethereum/execution-spec-tests repository, under the cancun directory at the eip1153_tstore path.