¿Por qué un lanzamiento de Solidity consume todo el gas?

Cuando throwhace una excepción, todo el gas se consume . ¿Cuál es el fundamento de esta decisión de diseño?

Respuestas (4)

Todo el gas se consume porque el EVM esencialmente solo tiene 1 excepción: sin gas.

Para ver esto más claro, eche un vistazo a la diferencia entre una excepción "pura" y un error debido a un código EVM incorrecto, con errores o no válido. Out of Gas es el primero. Ahora hay errores como subdesbordamiento de pila, JUMP no válido y código de operación no válido: pueden llamarse "excepciones", pero se parecen más a errores que a una excepción de EVM, porque el desarrollador del contrato no ha escrito un código de EVM válido de acuerdo con las reglas. de la EVM. Por ejemplo, un código de operación no válido es como escribir "clase" en lugar de "función" en Javascript: Javascript nativo no tiene "clase", a diferencia de un lenguaje como Java. Con el subdesbordamiento de la pila, es como si el desarrollador le dijera al EVM que agregue 2 números, pero el desarrollador no proporciona el segundo número.

Tenga en cuenta también cómo la "excepción" en el EVM es diferente de otros idiomas. Por ejemplo, no hay una excepción de división por cero en el EVM (aunque Solidity 0.4+ generará una excepción para esto). Suponiendo que el código EVM sea válido, no hay excepciones excepto por falta de gas.

Dado que solo hay una excepción de Sin gasolina, estos otros errores se comportaron como Sin gasolina. Esto es relativamente consistente con algunos principios de diseño de Ethereum de generalización y minimización de la complejidad. En otras palabras, al implementar el comportamiento de subdesbordamiento de pila, JUMP no válido y código de operación no válido, es más simple y más fácil para el protocolo reutilizar la implementación y el comportamiento de Out of Gas.

Otras respuestas han explicado cómo Solidity se compila throwen un JUMP no válido. (En su lugar, Serpent usa un código de operación no válido y lo llama en invalidlugar de throw).

EDITAR: El lanzamiento de Byzantium incluye EIP 140 , un nuevo código de operación nombrado REVERTen el EVM que:

proporciona una forma de detener la ejecución y revertir los cambios de estado, sin consumir todo el gas provisto y con la capacidad de devolver una razón.

throwestá siendo obsoleto a favor de revert(), require(),assert()

classes una palabra clave válida en javascript utilizada para definir una clase.
@0xcaff Gracias, sí, JavaScript también está evolucionando y se classagregó en ECMAScript 2015 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… (todavía lleva tiempo que los estándares ECMA sean ampliamente conocidos y adoptados).

La throwinstrucción Solidity se compila en una instrucción JUMP no válida (es decir, un salto a una ubicación no válida).

En el apartado 9.4.2 del Libro Amarillo se explica cómo funciona la parada excepcional , en el capítulo 8 se explica que en este caso no se reembolsa el gas.

En el capítulo 8 dice:

Al igual que con la creación del contrato, si la ejecución se detiene de manera excepcional (es decir, debido a un suministro de gas agotado, flujo insuficiente de la pila, destino de salto no válido o instrucción no válida), entonces no se reembolsa el gas a la persona que llama y el estado se revierte al punto inmediatamente antes de la transferencia de saldo (es decir, σ).

Y volviendo al capítulo 7:

Si tal excepción no ocurre, entonces el gas restante se reembolsa al originador y se permite que persista el estado ahora alterado.

En cuanto a por qué se ha decidido de esta manera, no tengo información al respecto.

En parte, creo que esta fue una decisión de seguridad para garantizar que enviar spam a la red con transacciones falsas le costara gasolina al remitente. Por ejemplo, si se reembolsa la gasolina después de un lanzamiento, un actor malicioso podría crear un contrato que consumiera algo de gasolina y luego lanzaría. Ese actor podría entonces enviar una o varias transacciones con un precio de gas alto y mucho gas, haciendo que sus transacciones tengan prioridad bajo los términos predeterminados del minero. Sus transacciones podrían consumir todo el gas de cada bloque, por lo que no se podrían realizar otras transacciones, y si se les devolviera el gas, podrían hacerlo de forma gratuita e indefinida. Con el consumo de gas, esto les costaría una gran cantidad de éter.

La throwinstrucción es un truco EVM que revierte todos los cambios realizados por la ejecución del contrato actual. Aprovecha la terminación excepcional de EVM que también consume todo el gas.

Eso no explica la razón de por qué está diseñado de esa manera. Muchos ejemplos en la documentación de Solidity se usan throwcomo si fuera la mejor manera de hacer las cosas. Pero claramente no lo es si le cuesta a las personas que llaman la tarifa máxima.
Según su explicación, debería costar como máximo tanto gas como el que ya se ha consumido en la transacción hasta el momento en que ocurrió la excepción (una implementación ingenua podría "deshacer" cada operación una a la vez).
Esto requeriría agregar un sistema para rastrear todos los cambios de estado, incluidos los de las llamadas a otros contratos, lo que no es posible de manera realista.