Volver a la página principal
martes 10 diciembre 2024
5

Cómo usar assert() en Solidity para comprobaciones internas críticas

assert() evalúa una condición booleana y detiene la ejecución si esta es false. A diferencia de require(), que está diseñado para validar entradas o restricciones del usuario, assert() se utiliza exclusivamente para verificar invariantes del contrato, es decir, propiedades internas que deben mantenerse válidas en todo momento.

Sintaxis

assert(condición);
  • condición: Una expresión booleana que debe ser true durante la ejecución del contrato.

Características principales:

1. Errores críticos: Se usa para identificar errores que indican fallos lógicos graves en el contrato.

2. Sin mensaje de error: A diferencia de require(), no permite mensajes personalizados.

3. Uso de gas: Consume todo el gas disponible si la condición es false.

Diferencias entre assert() y require()

Característica assert() require()
Uso principal Validar invariantes y errores internos. Validar entradas y restricciones.
Mensaje de error No admite mensajes personalizados. Permite incluir un mensaje.
Comportamiento al fallar Consume todo el gas y revierte cambios. Reembolsa el gas no utilizado.

Ejemplos de uso de assert()

1. Verificar invariantes críticas

pragma solidity ^0.8.0;

contract Invariantes {
    uint public total;

    // Incrementar el total
    function incrementar(uint _cantidad) public {
        total += _cantidad;
        // Verificar que el total nunca sea negativo
        assert(total >= _cantidad);
    }
}

En este ejemplo, assert() asegura que la variable total nunca sea negativa, lo cual sería un error lógico en el contrato.

2. Comprobación de estados internos

contract Estados {
    enum Estado { Inactivo, Activo }
    Estado public estado;

    constructor() {
        estado = Estado.Inactivo;
    }

    function activar() public {
        estado = Estado.Activo;
    }

    function verificarEstado() public view {
        // Asegurarse de que el estado siempre sea válido
        assert(estado == Estado.Inactivo || estado == Estado.Activo);
    }
}

Aquí, assert() verifica que el estado siempre sea válido dentro del conjunto de valores permitidos por la enumeración Estado.

3. Comprobación de balances en contratos financieros

contract Balances {
    mapping(address => uint) public balances;

    function transferir(address _destinatario, uint _cantidad) public {
        balances[msg.sender] -= _cantidad;
        balances[_destinatario] += _cantidad;

        // Comprobación de que el balance total sea coherente
        assert(balances[msg.sender] + balances[_destinatario] >= _cantidad);
    }
}

En este caso, assert() verifica que los balances sean consistentes después de una transferencia.

4. Validar límites críticos en variables

contract Limites {
    uint8 public contador;

    function incrementar() public {
        contador++;
        // Asegurar que no haya un desbordamiento
        assert(contador > 0);
    }
}

Antes de Solidity 0.8, assert() era utilizado frecuentemente para detectar desbordamientos aritméticos. A partir de esta versión, Solidity incluye comprobaciones automáticas de desbordamiento, pero assert() sigue siendo útil para verificar otras propiedades críticas.

Buenas prácticas para usar assert()

1. Uso exclusivo para invariantes: Limita el uso de assert() a comprobaciones internas que siempre deben cumplirse, independientemente de la entrada del usuario.

2. Evita abusos: No uses assert() para validaciones regulares; para ello, utiliza require().

3. Testeo exhaustivo: Asegúrate de probar el contrato a fondo para detectar posibles fallos en las condiciones verificadas por assert().

Consecuencias de una falla en assert()

1. Reversión completa: Detiene la ejecución y revierte todos los cambios realizados en la transacción.

2. Consumo de gas: Todo el gas proporcionado para la transacción se consume, lo que puede hacer costosa una falla de assert().

3. Indicativo de errores críticos: Una falla en assert() indica que hay un fallo lógico en el contrato que debe ser corregido.

Consideraciones importantes

  • Usa assert() únicamente para verificar invariantes y propiedades internas.
  • En contratos críticos, combina assert() con testeo automatizado para garantizar la estabilidad.
  • Revisa los cambios introducidos en Solidity 0.8 para evitar el uso redundante de assert() en situaciones ya protegidas, como desbordamientos aritméticos.

Referencias oficiales

Para más información sobre assert(), consulta la documentación oficial de Solidity.

Etiquetas:
solidity
Compartir:
Creado por:
Author photo

Jorge García

Fullstack developer