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
Я оставлю точную интерпретацию OpCodes кому-то другому и просто укажу, что это разные инструкции, поэтому следует ожидать разных реализаций.
Согласно этому: http://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions
Начиная с Метрополиса, revert;
будет возвращать неиспользованный газ, в то время как throw
продолжит потреблять весь доступный газ. С точки зрения изменения состояния контракта они одинаковы — все откатывается.
Надеюсь, поможет.
revert()
и другое throw
должно компилироваться в REVERT
код операции. Тогда я ожидаю, что в Метрополисе обработают этот код операции соответствующим образом (с возвратом газа). Я не понимаю, почему это привело бы к другому скомпилированному коду сейчас или когда-либо.revert()
вернет газ, а не REVERT
опкод, который используется как revert()
в throw
Solidity, так и нам нужна разница в байт-коде, спасибо!throw
дальше будет потребляться весь доступный газ? так можем ли мы заключить, что throw
неиспользованный газ не будет возвращен отправителю? @RobHitchensЭто revert
часто называют cheap throw
возвратом неиспользованного газа отправителю.
Если вас интересует подробный дизайн этой функции, посмотрите исходное обсуждение EIP-140 .
Окончание байт-кода после STOP не должно выполняться. Это аргументы конструктора. Что именно Solidity делает с ними и что там хранит? Только Гэвин может знать. Я думаю, это патч, чтобы получить все ваши средства
пользователь9402
throw
: github.com/ethereum/solidity/issues/1793 . Это может быть подмостками для обработки ошибок в будущем. Интересный вопрос!