EIP-140 REVERT opcode (REVERT instruction)
Final · EVM & execution · EIP status Final · created 2017-02-06
Adds a REVERT opcode to the EVM that halts execution and reverts all state changes made so far. It allows the failure reason to be passed back to the caller without consuming all remaining gas.
Why it is needed
Before this proposal, a smart contract had essentially only two ways to halt execution midway and revert it: deliberately burning all its gas (the fee for executing a transaction), or executing an invalid opcode to trigger an error. Both approaches consumed all remaining gas, so even a user who simply wanted to safely cancel a transaction because conditions were not met lost the entire fee. In addition, once execution reverted, all changes including logs disappeared, and there was no way to convey why it had been aborted. Users could not learn the reason a transaction failed, and wallets or apps could not display a failure reason either. REVERT solves both problems at once.
What changes
Today
- Reverting execution requires deliberately exhausting gas or executing an invalid opcode
- Either way consumes all remaining gas
- There is no way to pass a failure reason back to the caller
After EIP-140
- A single REVERT opcode halts execution and reverts state changes
- Only the memory cost is paid; remaining gas is not consumed
- The error message is passed to the caller as return data
Who is affected
- Users: Even if a transaction fails a condition check, the entire remaining gas is not lost
- Contract developer: Execution can be safely halted with an error message explaining the reason when a condition is not met
- Wallet & app developers: The error message can be read from the failed call's return data and shown to the user
- Client teams: The EVM must implement the new opcode 0xfd
In depth
Opcode definition and stack behavior
Starting from blocks where block.number >= BYZANTIUM_FORK_BLKNUM, the REVERT opcode is introduced at position 0xfd. It pops two items off the stack, with memory_offset on top and memory_length below it. Since it halts execution, nothing is pushed onto the stack. The source calls the byte sequence pointed to by memory_offset and memory_length the error message. Memory access and memory cost calculation are identical to RETURN.
Gas cost
REVERT costs the same as RETURN. The rollback itself does not consume remaining gas, and the contract only pays the memory cost. However, if there is insufficient gas to cover the REVERT cost or a stack underflow occurs, it is treated the same as a normal out of gas exception, consuming all remaining gas.
Handling on the caller's side
When REVERT is executed, execution halts, is treated as a failure, and state changes are rolled back. As with any other failure, when the callee reverts, the caller's call opcode returns 0 on the stack. The error message can be read from the caller's return data buffer and is also copied into the output region, meaning it is handled the same way as ordinary return data.
Behavior in CREATE and CREATE2
If REVERT is executed inside a CREATE or CREATE2 call, the code is not deployed, 0 is pushed onto the stack, and the error message can be read from the return data buffer. Contract creation failures can now convey a reason the same way ordinary call failures do.
The content of the error message is left undefined
This EIP does not define the format of the content of the optionally passed memory region, that is, the error message. The source leaves this as a candidate for a separate Informational EIP. This EIP only provides a channel for passing a byte sequence that can be interpreted as an error code or message.
Backwards compatibility and test cases
This has no effect on previously created contracts, except in the case where 0xfd already appears as an opcode in their code. The source test case specifies that the given bytecode must return 0x726576657274206d657373616765 as REVERT data, leave storage key 0x0 unset, and consume a total of 20024 gas. It is a case that verifies both that the storage write is rolled back and that the message is passed along. This EIP has been finalized with Final status.