Почему `throw` и `revert()` создают разные байт-коды?

throwи revert()оба компилируются в revertоперацию (код операции 0xfd). Согласно документам :

Ключевое слово throw также можно использовать как альтернативу revert().

Почему же тогда следующий договор

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

производит другой байт-код, если я использую revert()вместо throwв примере выше? Я использую Remix с Solidity 0.4.13+commit.0fb4cb1a.Emscripten.clang. Это результирующие коды операций:

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 

Мы видим, что последние инструкции отличаются. В то время как версия с throwокончаниями на

0x627A7A723058
KECCAK256
0x4a
PUSH32
0x5473469C00A2379987B5AF61DFF50F8FABE3B71589C4D2BBB53073BEB9D10029

версия с revert()концами на

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
Не уверен, что причина в этом, но в документах Solidity также говорится о revert() . В будущем можно будет также включить сведения об ошибке в вызов revert. И есть открытый вопрос о полном отказе от поддержки throw: github.com/ethereum/solidity/issues/1793 . Это может быть подмостками для обработки ошибок в будущем. Интересный вопрос!

Ответы (3)

Я оставлю точную интерпретацию OpCodes кому-то другому и просто укажу, что это разные инструкции, поэтому следует ожидать разных реализаций.

Согласно этому: http://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions

Начиная с Метрополиса, revert;будет возвращать неиспользованный газ, в то время как throwпродолжит потреблять весь доступный газ. С точки зрения изменения состояния контракта они одинаковы — все откатывается.

Надеюсь, поможет.

Спасибо. Однако я понимаю эти документы так, что и то, revert()и другое throwдолжно компилироваться в REVERTкод операции. Тогда я ожидаю, что в Метрополисе обработают этот код операции соответствующим образом (с возвратом газа). Я не понимаю, почему это привело бы к другому скомпилированному коду сейчас или когда-либо.
Я могу ошибаться. Моя интуиция подсказывает, что мы не можем получить разные результаты из одинакового кода. Поскольку revert и throw do (будут) выполнять немного разные операции по отношению к газу, следует ожидать различия в коде. Иными словами, если бы скомпилированный код был идентичен, как EVM узнал бы, что делать с газом?
ок, спасибо, теперь я добрался до своего недоразумения: солидность revert()вернет газ, а не REVERTопкод, который используется как revert()в throwSolidity, так и нам нужна разница в байт-коде, спасибо!
Как throwдальше будет потребляться весь доступный газ? так можем ли мы заключить, что throwнеиспользованный газ не будет возвращен отправителю? @RobHitchens

Это revertчасто называют cheap throwвозвратом неиспользованного газа отправителю.

Если вас интересует подробный дизайн этой функции, посмотрите исходное обсуждение EIP-140 .

Окончание байт-кода после STOP не должно выполняться. Это аргументы конструктора. Что именно Solidity делает с ними и что там хранит? Только Гэвин может знать. Я думаю, это патч, чтобы получить все ваши средства