¿Se revierte una transacción completa cuando ocurre el lanzamiento?

Tengo un contrato que llama a otro contrato que llama a otro. Si hay un lanzamiento (o un error de falta de gas) que ocurre en algún lugar del segundo contrato, ¿ se revierte toda la transacción o son solo las cosas en el segundo y tercer contrato las que lo hacen, mientras que la ejecución del primer contrato ¿sigue en pie?

Respuestas (3)

En Solidity, por defecto, sí.

En el nivel de EVM, un lanzamiento (mal salto, sin gas o cualquier otra excepción) solo revierte la llamada en la que se encuentra. Solidity continúa útilmente la excepción en la pila hasta que todo se deshace.

Es posible, usando un código de nivel inferior (específicamente, address.call()), para evitar esto. Aquí hay un ejemplo de esto que se usa como una construcción improvisada de intento y captura.

Si hago una llamada dentro de mi contrato, a un contrato desconocido, todavía puedo estar seguro de que el contrato desconocido no tiene la capacidad de dejar mi contrato en un estado intermedio.
Eso es correcto. A menos que use deliberadamente address.call(), la excepción se propagará hacia abajo automáticamente. Dicho esto, es posible que desee investigar la situación en profundidad. Un contrato desconocido puede llamar más tarde a su contrato nuevamente (el ataque de reentrada), y su contrato estará para ese momento en un estado intermedio.
Tengo que usar address.call() porque es un contrato 'desconocido', pero parece que todavía estoy a salvo de que mi código se quede a medio hacer. Si tiran, las únicas opciones son: 1 reversión total. O 2 la llamada de address.call() se revierte y mi código continúa como si nada hubiera pasado. (Ignorando la reentrada de la que me he protegido de otras maneras)

Para complementar la respuesta de @Matthew, depende de cómo se realice la llamada en Solidity.

Si Cllama D.foo()y foohace un throw, entonces sí, se revierte toda la transacción.

Si Chace una "llamada sin procesar de nivel inferior" como D.call(bytes4(sha3('foo()'))), y foohace un throw, entonces solo fooy sus subllamadas se revierten. Esto se debe a que una llamada sin formato no propaga ninguna excepción: una llamada sin formato D.callsolo devuelve un valor booleano que indica si la llamada tuvo éxito o encontró una excepción.


Más detalles

En Solidity, a throwprovoca una excepción al generar un código de bytes que conduce a un destino de salto no válido . (Para los demás casos, consulte Todos los casos en los que Solidity se compila en un destino de salto no válido ).

Desde la perspectiva de Solidity, una excepción que no se trague o que no se detecte o no se controle hará que se revierta toda la transacción.

Actualmente no hay forma de detectar una excepción en Solidity, por lo que una excepción, como throw, hará que se revierta toda la transacción.

Sin embargo, las llamadas sin procesar "tragan" excepciones: las llamadas sin procesar no propagan excepciones y es por eso que solo se revertirán las subllamadas.

Es toda la transacción la que se revierte.

Además, todo el gas adjunto a la transacción (incluido el restante) va al minero.

Por lo general, se revierte toda la transacción, pero también puede evitar que esto suceda. Ver la respuesta de Mateo.