throw
y revert()
ambos están compilando la revert
operación (opcode 0xfd
). Según los documentos :
La palabra clave throw también se puede utilizar como alternativa a revert().
¿Por qué entonces el siguiente contrato
contract test {
function () {
throw;
//revert();
}
}
produce un código de bytes diferente si lo uso revert()
en lugar del throw
ejemplo anterior? Estoy usando Remix con Solidity 0.4.13+commit.0fb4cb1a.Emscripten.clang. Estos son los códigos de operación resultantes:
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
Vemos que las últimas instrucciones son diferentes. Mientras que la versión con throw
termina en
0x627A7A723058
KECCAK256
0x4a
PUSH32
0x5473469C00A2379987B5AF61DFF50F8FABE3B71589C4D2BBB53073BEB9D10029
la versión con revert()
extremos en
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
Dejaré la interpretación precisa de los OpCodes a otra persona y solo señalaré que son instrucciones diferentes, por lo que se esperan diferentes implementaciones.
De acuerdo con esto: http://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions
Empezando por Metropolis, revert;
devolverá el gas no utilizado mientras throw
que seguirá consumiendo todo el gas disponible. En términos de cambios de estado del contrato, son lo mismo: todo se revierte.
Espero eso ayude.
revert()
deben throw
compilarse en un REVERT
código de operación. Entonces esperaría que Metropolis maneje este código de operación de manera correspondiente (con un reembolso de gasolina). No veo por qué esto conduciría a un código compilado diferente ahora o nunca.revert()
devolverá el gas, no el REVERT
código de operación que usan ambos revert()
y throw
en Solidity, por lo tanto, necesitamos la diferencia en el código de bytes, ¡gracias!throw
seguirán consumiendo todo el gas disponible? Entonces, ¿ podemos concluir que throw
no devolverá el gas no utilizado al remitente?@RobHitchensA revert
menudo se denomina cheap throw
como que reembolsa el gas no utilizado al remitente.
Si está interesado en el diseño detallado de esta función, consulte la discusión original de EIP-140 .
No se debe ejecutar el final del bytecode después de STOP. Son argumentos de constructor. ¿Qué hace exactamente Solidity con ellos y qué almacena allí? Solo Gavin puede saberlo. Supongo que es un parche para tener todos tus fondos.
usuario9402
throw
: github.com/ethereum/solidity/issues/1793 . Podría ser un andamiaje para el manejo de errores en el futuro. ¡Interesante pregunta!