Publicado en
En nuestra columna anterior escribíamos acerca de la Semántica Formal y los Lenguajes de Modelado. Hoy vincularemos lo anterior con el tema de esta edición, el blockchain.
Algo que permite definir brevemente blockchain, es decir que se trata de una implementación exitosa de la contabilidad de partida triple, con un libro de registros incremental, inmutable y distribuido, almacenado y protegido criptográficamente por una red de nodos pares que cuenta con mecanismos de comunicación y consenso para alcanzar (eventualmente) una única versión del historial de transacciones.
Dos de las principales características blockchain son el ser…
-
Inmutable: Una vez que se valida y se guarda una transacción en un blockchain, ya no se puede modificar.
-
Distribuido: Toda la historia de transacciones desde el primer bloque generado (el “bloque génesis”) está replicada en todos los nodos de la red del blockchain y de manera perpetua (razón por la cual puede volverse costoso).
Por otro lado, una de las aplicaciones del blockchain es el Bitcoin (efectivo virtual), pero hay otras como el registro descentralizado de eventos, y el desarrollo de “contratos inteligentes” o “aplicaciones descentralizadas”, el cual describimos a continuación.
Un contrato Inteligente (smart contract) es un protocolo de transacción computarizada que ejecuta los términos de un contrato. Los objetivos generales del diseño de un contrato inteligente son satisfacer las condiciones comunes contractuales (como los términos de pago, gravámenes, confidencialidad e incluso reforzamiento), minimizar excepciones maliciosas o accidentales y minimizar la necesidad de intermediarios de confianza (como intermediarios financieros, acaparadores, o distribuidores)”[1].
Los contratos inteligentes en un blockchain público son trazables e irreversibles. Esto quiere decir que el lanzamiento (deployment) y todas las interacciones con el contrato inteligente se registran como transacciones en el blockchain, y por ende son irreversibles (por la propiedad de inmutabilidad).
Actualmente los contratos inteligentes se implementan como un script en un blockchain con capacidad de scripting “Turing complete” (como lo describimos en el artículo “La prueba de software y los special purpose languages”[2] en el número 54 de esta publicación, un lenguaje “Turing complete” es aquel que puede procesar exactamente lo que procesaría una máquina de Turing, y por extensión cualquier computadora). El código de los contratos inteligentes mismos se almacena en los metadatos de una transacción en el blockchain, lo que los vuelve inmutables, volviendo imposible corregir cualquier bug que hubiera quedado sin detectar en el contrato.
Riesgos y consecuencias de defectos
Los contratos inteligentes se desarrollan en el contexto de un blockchain y tienen la capacidad de transferir valor (monetario y no monetario) lo que implica en particular, que es muy importante destinar un esfuerzo muy significativo al aseguramiento y control de calidad (prueba de software) de un contrato antes de liberarlo, como ya ocurre en el sector aeroespacial. El impacto de no hacerlo pueden mostrarlo los siguientes errores épicos en contratos inteligentes:
-
El defecto batch overflow del ERC20[3]. La mayoría de los tokens existentes están creados sobre el blockchain de Ethereum bajo la plantilla del ERC20, que especifica un API para poder crear, transferir y disponer de tokens fungibles (intercambiables). Una implementación muy utilizada del ERC20 tiene una vulnerabilidad que permite a cualquier usuario crear una cantidad enorme de tokens y enviarlos a su cartera de Ethereum. Varios tokens fueron afectados, forzando a los mercados (exchanges) a quitarlos de su listado para transacciones. El problema raíz de este contrato fue un clásico buffer-overflow de un número entero sin signo.
-
Problema en la cartera de Parity [4]: Una serie de defectos, no en los contratos inteligentes, sino en las carteras de criptomonedas ocasionó que se perdieran alrededor de $280MUSD en Ether (una criptomoneda bastante difundida) por contener un bug que ocasionó que las carteras multifirma con el bug (las carteras multifirma son carteras que requieren de más de una firma para transferir fondos; son muy utilizadas en fondos y empresas) permitían que cualquier usuario se convirtiera en un dueño de la cartera. Un usuario que encontró el bug, quiso solucionarlo y terminó eliminando la firma que se había convertido en co-dueña de los fondos, esencialmente impidiendo que los usuarios afectados puedan disponer de sus recursos.
-
El fiasco de la DAO [5]: La DAO (Decentralized Autonomous Organization) es un proyecto del 2016 en la red de Ethereum que recaudó alrededor de $150MUSD en Ether. Incluía un defecto que permitió que un tercero drenara cierta cantidad de Ether en otro contrato inteligente. Al final, la corrección que se adoptó fue un “hard fork” que es una bifurcación del blockchain que dividió el blockchain de Ethereum en dos blockchains independientes: Ethereum (ETH) y Ethereum Classic (ETC), causando una reducción en el valor del Ether.
El ciclo de vida de los contratos inteligentes (Decentralized Applications o “DAPPS”) dista mucho del ciclo de vida de las aplicaciones convencionales, por ejemplo las “Apps” para teléfonos móviles, donde cada 1 o 2 semanas se puede recibir una actualización de seguridad. Esta diferencia en el ciclo de vida de ambos casos y las implicaciones de los defectos en cada uno, demuestra que la aproximación a la calidad en el desarrollo de aplicaciones móviles debe ser muy distinto a aquella de las DAPPS.
Estrategias de QA para contratos inteligentes
Por todo lo anterior, vemos varias alternativas para el Aseguramiento y Control de Calidad de contratos inteligentes:
Verificación Formal. La verificación de modelos o comprobación de modelos (model checking) es un método que permite comprobar si el diseño de un sistema SIEMPRE cumple con la especificación del mismo.
El método involucra los siguientes elementos:
-
El modelo. El sistema debe ser modelado con un lenguaje formal; en muchos casos se utiliza algún tipo de grafo o autómata. Un contrato inteligente se puede representar como un grafo de control donde los nodos representan bloques de código y las aristas denotan los flujos de control.
-
La especificación escrita o traducida a un lenguaje formal. La mayoría de los enfoques utilizan alguna variante de Lógica Temporal Proposicional. El punto de partida es la negación de la especificación.
-
Un algoritmo para la transformación de una fórmula en el lenguaje de especificación en un grafo compatible con el utilizado para modelar el sistema.
-
Un algoritmo que permite combinar ambos grafos. El grafo resultante acepta todos los comportamientos del modelo que cumplen con la negación de la especificación. El resultado esperado es el grafo vacío, lo cual indica que no existe un solo comportamiento del modelo que no cumpla la especificación; en caso de no obtener el grafo vacío se podrá realizar un recorrido del mismo para obtener un contraejemplo o “testigo”, lo cual es un comportamiento del modelo que no cumple la especificación.
En la figura 1 podemos ver de manera esquemática el método, donde en el contraejemplo se muestran las transiciones de estado (cada En es un estado, y -> representa la transición del estado En al Em) que llevan al comportamiento que no cumple con la especificación.
Prueba Convencional. Ya que la verificación formal todavía puede dejar huecos en la calidad de los contratos inteligentes, se deben aplicar pruebas unitarias, de integración y de sistema, utilizando técnicas de diseño de caja negra y de caja blanca. Es necesario tener un enfoque en probar:
-
El contrato inteligente en sí mismo. Es necesario que validemos que las librerías que se usan estén libres de defectos conocidos. El contrato incluye funciones (que son programadas) que se realizan sobre los contratos inteligentes; debemos aplicar las técnicas conocidas de caja negra y caja blanca para probar su correcto funcionamiento. Esto representaría una prueba unitaria.
-
Las interacciones entre contratos inteligentes. Dado que es posible que un contrato inteligente interactúe con otro contrato inteligente, en nuestras pruebas de integración debemos determinar una matriz de interacción y diseñar pruebas que permitan validar esas interacciones detalladamente.
-
Las interacciones de los contratos inteligentes con los wallets genéricos. Un wallet es el software que permite almacenar y transferir valor (por ejemplo, criptomonedas). Típicamente, la manera de interactuar con un contrato inteligente es a través de un wallet genérico que pone al alcance de un usuario el API (Application Programming Inteface) público del contrato. Este es otro tipo de interacción que debemos considerar en nuestra matriz de interacción mencionada en el punto anterior para nuestras pruebas de integración.
-
Las interacciones de los contratos inteligentes con los oráculos de información. Un oráculo de información es una fuente de datos externa, típicamente de un tercero, que ofrece información al contrato inteligente para la toma de decisiones. También estas interacciones deberán estar definidas en nuestra matriz de interacción y es de vital importancia probarlas no sólo para validar la correcta funcionalidad del contrato inteligente sino también para verificar que éste sea resiliente a pesar de fallas en el suministro de información.
-
La interacción de los contratos inteligentes con las aplicaciones frontend. En aplicaciones donde el blockchain y los contratos inteligentes se manejen como el backend de un proceso, se requerirán aplicaciones a través de las cuales los usuarios interactúen. Esto implica las últimas pruebas de integración y las pruebas de sistema. Debemos analizar la interacción entre los contratos inteligentes y estas aplicaciones de frontend que pueden ser Web, móviles o de otro tipo para definir los escenarios de uso y probarlos desde diferentes perspectivas.
Análisis Estático de Código. Puede ser una herramienta que ayude a determinar la “salud” del código de los contratos inteligentes. También para los contratos inteligentes existen buenas prácticas de programación, y violaciones a muchas de estas reglas pueden ser detectadas automáticamente por herramientas. Existen por ejemplo reglas de estilo que contribuyen a la mantenibilidad del código; algunas de estas reglas son el uso de líneas en blanco después de cada contrato, máxima cantidad de caracteres en líneas de código, y llamados a funciones con argumentos muy largos. Adicional a las reglas de estilo los contratos inteligentes deberán programarse cuidando elementos como seguridad, manejo de excepciones, y consumo de “gas” (como muy probablemente habrán leído en otros artículos en esta misma revista, el gas es el precio que se paga a la plataforma de blockchain por realizar las transacciones). Muchos de estos elementos son buenas prácticas de programación que es posible definir como reglas para que una herramienta (comercial, de código abierto o propietaria) las detecte y nos de advertencias de riesgos potenciales en nuestro código.
Abrir código. De forma alternativa, para obtener mayor confianza en nuestros contratos algunas organizaciones podrían publicar como código abierto algunos de los componentes de los contratos buscando que más desarrolladores puedan mejorar estos componentes o bien buscar una estrategia de “bounties” mediante la cual se pueda reservar una bolsa de premios para aquellos que de forma sistemática y reproducible encuentren defectos y procesos de explotación de los mismos.
Conclusión
En resumen, el proceso de aseguramiento de calidad durante el desarrollo e implementación de contratos inteligentes es crítico para minimizar riesgos que afecten el patrimonio de los usuarios del mismo. De forma general podemos considerar que la mayoría de las aplicaciones basadas en blockchain tienen al menos el nivel de criticidad de las aplicaciones del sector financiero; si a esto le sumamos que cada nueva liberación del software nos puede ocasionar gastos importantes para la liberación (cada vez se consumirá gas), vemos que el esfuerzo empleado en seguir varias de las estrategias de aseguramiento y control de calidad aquí descritas puede tener un alto retorno de la inversión.
Se invita al lector que se acerque con profesionales de validación de software para determinar los requerimientos y ejecutar las actividades de aseguramiento y control de calidad de sus proyectos que implican desarrollo de contratos inteligentes.
Referencias
-
N. Szabo. Smart Contracts: Building Blocks for Digital Markets”. http://swgu.ru/x8
-
L. León. “La prueba de software y los special purpose languages, parte 6”. SG Software Guru #54. http://swgu.ru/xh
-
“New batchOverflow Bug in Multiple ERC20 Smart Contracts”. PeckShield. http://swgu.ru/xi
-
I. Thompson. “Parity calamity! Wallet code bug destroys $280m in Ethereum”. The Register, noviembre 2017. http://swgu.ru/xj
-
D. Siegel. “Understanding The DAO Attack”. Coindesk, junio 2016. http://swgu.ru/xk
Luis Vinicio León Carrillo es Director General y co-fundador de e-Quallity. Antes de fundar e-Quallity fue profesor-investigador en la universidad jesuita ITESO durante varios lustros, que incluyeron una estancia de posgrado en Alemania, durante la cual abordó aspectos relacionados con el Testing y los formal methods and languages.
Aarón Moreno Monroy es Director de Operaciones y co-fundador de e-Quallity. Fue profesor de asignatura en la universidad ITESO. Estudió su Maestría en el CINVESTAV; su trabajo de tesis tuvo que ver con verificación formal, la cual aborda la prueba de software utilizando modelos matemáticos.
Rogelio Reyna es Ingeniero en Sistemas Electrónicos; tiene 14 años de experiencia en desarrollo de sistemas embebidos, automatización industrial y validación de device drivers. Actualmente es Director General de Smart Agreements Technologies, empresa de la que es co-fundador y cuyos servicios incluyen el desarrollo de contratos inteligentes en esquemas como “Manufacturing as a Service”.
- Log in to post comments