Características de Solidity 0.6.x: La declaración Try / Catch

Publicado originalmente en el blog de Solidity Ethereum Foundation

La sintaxis try / catch introducida en 0.6.0 es posiblemente el mayor salto en las capacidades de manejo de errores en Solidity, ya que las cadenas de razón para revert y require se lanzaron en v0. 4.22. Tanto try como catch han sido palabras clave reservadas desde v0.5.9, y ahora podemos usarlas para manejar fallas en llamadas de función externas sin retroceder la transacción completa (los cambios de estado en la función llamada todavía se revierten, pero los de la función que llama no lo están).

Nos estamos alejando un paso del enfoque purista de todo o nada en el ciclo de vida de una transacción, que no alcanza el comportamiento práctico que a menudo queremos.

Manejo de fallas de llamadas externas

La declaración try / catch le permite reaccionar ante llamadas externas fallidas y llamadas de creación de contrato , por lo que no puede usarla para la función interna llamadas. Tenga en cuenta que para envolver una llamada de función pública dentro del mismo contrato con try / catch, se puede hacer externa llamando a la función con this .

El siguiente ejemplo demuestra cómo se usa try / catch en un patrón de fábrica donde la creación de contratos puede fallar. El siguiente contrato CharitySplitter requiere una propiedad de dirección obligatoria, _owner , en su constructor.

Existe un contrato de fábrica, CharitySplitterFactory , que se utiliza para crear y administrar instancias de CharitySplitter . En la fábrica, podemos envolver el nuevo CharitySplitter (charityOwner) en un try / catch como un mecanismo a prueba de fallos para cuando ese constructor pueda fallar debido a que se pasa un charityOwner vacío.

Tenga en cuenta que con try / catch, solo se detectan las excepciones que ocurren dentro de la propia llamada externa. Los errores dentro de la expresión no se detectan; por ejemplo, si el parámetro de entrada para el nuevo CharitySplitter es en sí mismo parte de una llamada interna, no se detectarán los errores que genere.

Un ejemplo que demuestra este comportamiento es la función createCharitySplitter modificada. Aquí, el parámetro de entrada del constructor CharitySplitter se recupera dinámicamente de otra función: getCharityOwner . Si esa función se revierte, en este ejemplo con & quot; revert-required-for-testing & quot; , no se detectará en la declaración try / catch.

Recuperando el mensaje de error

Podemos extender aún más la lógica try / catch en la función createCharitySplitter para recuperar el mensaje de error si uno fue emitido por un revert o require y emitirlo en un evento. Hay dos formas de lograrlo:

1. Usando “ error de captura (motivo de memoria de cadena) & # x27;

Esto emite el siguiente evento en un constructor fallido require error:

2. Usando “ catch (motivo de memoria de bytes) & # x27;

Esto emite el siguiente evento en un constructor fallido require error:

Los dos métodos anteriores para recuperar la cadena de error producen un resultado similar. La diferencia es que el segundo método no decodifica ABI la cadena de error. La ventaja del segundo método es que también se ejecuta si la decodificación ABI de la cadena de error falla o si no se proporcionó ninguna razón.

Planes futuros

Hay planes para lanzar soporte para tipos de error, lo que significa que podremos declarar errores de manera similar a los eventos, lo que nos permitirá detectar diferentes tipos de errores, por ejemplo: