12

throw and revert() are both compiling to the revert operation (opcode 0xfd). According to the docs:

The throw keyword can also be used as an alternative to revert().

Why is it then that the following contract

contract test {
    function () {
        throw;
        //revert();
    }
}

produces different bytecode if I use revert() instead of throw in the example above? I am using Remix with Solidity 0.4.13+commit.0fb4cb1a.Emscripten.clang. These are the resulting opcodes:

using throw:    PUSH1 0x60 PUSH1 0x40 MSTORE CALLVALUE ISZERO PUSH1 0xE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST JUMPDEST PUSH1 0x47 DUP1 PUSH1 0x1C PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x60 PUSH1 0x40 MSTORE JUMPDEST CALLVALUE ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x19 JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST JUMP JUMPDEST STOP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x4a PUSH32 0x5473469C00A2379987B5AF61DFF50F8FABE3B71589C4D2BBB53073BEB9D10029 
using revert(): PUSH1 0x60 PUSH1 0x40 MSTORE CALLVALUE ISZERO PUSH1 0xE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST JUMPDEST PUSH1 0x47 DUP1 PUSH1 0x1C PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x60 PUSH1 0x40 MSTORE JUMPDEST CALLVALUE ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x19 JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST JUMP JUMPDEST STOP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x5f 0xef 0xc4 0xac 0x4c STATICCALL DUP15 TIMESTAMP CODECOPY PUSH10 0x17070269221C62F6F5D4 0xba 0xe1 BALANCE BYTE 0xf7 EQ 0xca SWAP6 SWAP13 0xd0 0x27 0x24 STOP 0x29 

We see that the last instructions are different. While the version with throw ends on

0x627A7A723058
KECCAK256
0x4a
PUSH32
0x5473469C00A2379987B5AF61DFF50F8FABE3B71589C4D2BBB53073BEB9D10029

the version with revert() ends on

0x627A7A723058
KECCAK256
0x5f
0xef
0xc4
0xac
0x4c
STATICCALL
DUP15
TIMESTAMP
CODECOPY
PUSH10
0x17070269221C62F6F5D4
0xba
0xe1
BALANCE
BYTE
0xf7
EQ
0xca
SWAP6
SWAP13
0xd0
0x27
0x24
STOP
0x29
  • Not sure if this is the reason, but the Solidity docs also say of revert(), In the future it might be possible to also include details about the error in a call to revert. And there is an open issue about completely deprecating throw: github.com/ethereum/solidity/issues/1793. It might be scaffolding for error handling down the road. Interesting question! – user9402 Jul 11 '17 at 14:08
15

I'll leave the precise interpretation of the OpCodes to someone else and just point out that they are different instructions so different implementations are to be expected.

According to this: http://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions

Starting with Metropolis, revert; will return unused gas whereas throw will continue to consume all available gas. In terms of contract state changes, they are the same - everything gets rolled back.

Hope it helps.

  • Thank you. My understanding of those docs is however that both revert() and throw should compile into a REVERT opcode. Then I would expect at Metropolis to handle this opcode correspondingly (with a gas refund). I do not see why this would lead to different compiled code now or ever. – Validity Labs - Sebastian Jul 11 '17 at 14:30
  • I may be mistaken. My intuition says we can't get different results from identical code. Since revert and throw do (will) perform slightly different operations with respect to the gas, a difference in the code is to be expected. Put another way, if the compiled code was identical, how would the EVM know what to do with the gas? – Rob Hitchens - B9lab Jul 11 '17 at 15:16
  • 1
    ok thanks, now I got to my misunderstanding: the solidity revert() will return the gas, not the REVERT opcode which is used by both revert() and throw in Solidity, hence we need the difference in bytecode, thanks! – Validity Labs - Sebastian Jul 11 '17 at 17:05
  • How throw will continue to consume all available gas? so can we conclude that throw won't return unused gas to the sender?@RobHitchens – alper Mar 7 '18 at 8:36
5

The revert is often referred to as cheap throw as it refunds unused gas to the sender.

If you are interested in the detailed design of this feature please look at the original EIP-140 discussion.

-1

Ending of the bytecode after STOP is not to be run. It's constructor arguments. What exactly does Solidity do with them and what does it store there? Only Gavin may know. My guess, it's a patch to have all your funds

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.