Introducción rápida al invariant Testing

Introducción

En el dinámico y creciente universo de las Finanzas Descentralizadas (DeFi), la estabilidad y confiabilidad de los protocolos son elementos cruciales para garantizar la seguridad de los fondos y la integridad del ecosistema. En este contexto, las "invariantes" emergen como piezas fundamentales que establecen reglas inviolables, cuyo cumplimiento es esencial en cualquier situación o estado del sistema.

Este artículo aborda el concepto de "invariantes", explorando su importancia en DeFi y destacando algunas reglas comunes. Desde la sobrecolateralización hasta restricciones sobre retiros, estas invariantes actúan como guardianes de la coherencia en un mundo donde la confianza y la transparencia son imperativas.

¿Qué es una invariante?

Una invariante es una regla que se espera que sea válida en todo momento, sin importar el estado o las circunstancias de un sistema. Proporcionan restricciones y criterios de consistencia que ayudan a garantizar su integridad y coherencia.

Algunas invariantes que encontramos comúnmente en DeFi son:

  1. Un protocolo siempre debe estar sobrecolateralizado.

  2. Un usuario nunca debe de poder retirar más dinero del que ha depositado + las recompensas o tarifas que le corresponden.

  3. En una lotería solo puede haber un ganador.

Si podemos demostrar que la verdad de un sistema no es verdad en todos los escenarios válidos posibles, tenemos que asumir que alguien se aprovechará de ello en mainnet, especialmente si hay dinero de por medio.

Hacer pruebas de invariantes nos permite descubrir edge cases y bugs difíciles de encontrar que podrían no haber sido identificados mediante pruebas convencionales, permitiendo así corregir los problemas antes de que sean explotados por usuarios maliciosos.

¿Cómo se hace?

Fuzzing

El Fuzz Testing o Fuzzing es una técnica en la que se introducen datos aleatorios o inesperados en un programa para detectar fallos o vulnerabilidades.

Consiste en alimentar el software con entradas generadas de forma aleatoria o modificada, con el objetivo de provocar comportamientos inesperados y descubrir errores o posibles vulnerabilidades.

Durante una ejecución de prueba de invariantes, el fuzzer ejecuta todas las funciones en todos los contratos (mientras no lo hallamos limitado). Este genera secuencias de llamadas aleatorias con datos aleatorios y verifica las invariantes después de cada llamada. Si alguna secuencia de llamadas rompe una invariante, las pruebas fallan.

Puede resultar desafiante dirigir el caos del fuzzer hacia un conjunto de pruebas significativas y confiables, ya que pueden generar un gran volumen de casos de prueba que no son efectivos para encontrar errores.

Para hacer las pruebas más eficientes, se puede optimizar el proceso al priorizar los casos de prueba que tienen una mayor probabilidad de revelar vulnerabilidades o dirigirse a áreas específicas del programa donde es más probable que existan errores.

Handler pattern

Una manera de optimizarlo es siguiendo el Handler pattern expuesto en how to structure an invariant test suite using a Handler pattern.

Un "handler" es un contrato wrapper que utilizaremos para interactuar con nuestro contrato inicial en pruebas. En lugar de exponer las funciones de nuestro contrato directamente al fuzzer, apuntaremos a nuestro contrato handler y este llamará a las funciones específicas del contrato inicial que hayamos añadido.

Cabe mencionar que cuando utilizamos un handler, comenzamos a introducir suposiciones sobre el sistema en las pruebas. Es necesario limitar el sistema para probarlo de manera significativa, pero también es importante detenerse y considerar las suposiciones que estamos haciendo en el proceso, y no terminar probando un sistema que no se parece en nada al mundo real.

Conclusión

En conclusión, la exploración de invariantes y las técnicas avanzadas de prueba desempeñan un papel importante en la fortaleza y seguridad de los protocolos DeFi. La combinación de Fuzz Testing y el Handler pattern emerge como un enfoque dinámico para descubrir vulnerabilidades, revelando posibles escenarios críticos y fortaleciendo la resiliencia de los contratos inteligentes ante posibles amenazas. Este viaje nos recuerda la necesidad constante de innovación y rigor en las prácticas de prueba para garantizar la integridad de los protocolos y la protección de los usuarios en un mundo financiero cada vez más digital y descentralizado.

Fuentes