Tolerancia a Fallas Bizantinas, o BFT por sus siglas en inglés, es uno de los conceptos más importantes de la blockchain y quizás uno de los menos conocidos. Sin ella, no sería posible la tecnología blockchain tal y como la conocemos.
El término de falla bizantina, se deriva del Problema de los Generales Bizantinos (PGB). Este problema lógico supone, en pocas palabras, que los actores deben acordar una estrategia concertada para evitar una falla catastrófica del sistema. Pero existe la posibilidad de que dentro del sistema haya actores que pueden no ser confiables. Ante este hecho, el sistema debe crear mecanismos que garanticen que esos actores maliciosos no puedan conducir a la falla sin más remedio. La creación de esos mecanismos son los que precisamente otorgan la tolerancia a las fallas bizantinas.
Puede sonar algo sencillo, pero la realidad es muy distinta. Alcanzar la Tolerancia a Fallas Bizantinas, es uno de los desafíos más difíciles de la informática. Hasta el punto, que el primer diseño en resolverlo de forma satisfactoria fue el Bitcoin, de Satoshi Nakamoto. Con ello marcó un hito, uno que ha acompañado a la tecnología blockchain hasta ahora.
La Tolerancia a Fallas Bizantinas, es la capacidad de un sistema informático distribuido, de soportar faltas bizantinas.
Estas fallas pueden ser:
- Fallas de consenso.
- Fallas de validación.
- Fallas de verificación de datos.
- Fallas en el protocolo de respuesta frente a situaciones de la red.
Esta tolerancia está ligada a la capacidad de que la red, como un todo, pueda crear un mecanismo de consenso. La finalidad de este es dar una respuesta coherente a la falla del sistema.
¿Cómo funciona la Tolerancia a Fallas Bizantinas?
La Tolerancia a Fallas Bizantinas funciona definiendo un conjunto de reglas que permite resolver el Problema de los Generales Bizantinos de forma satisfactoria. Alcanzar esto es complejo, pues estas clases de fallos no implica restricciones. Esta situación hace al problema más complejo y difícil de tratar. Sin embargo, en muchos sistemas informáticos esta tolerancia es un requisito. Por ello, para poder alcanzar este objetivo, un sistema tolerante a fallos bizantinos debe cumplir como mínimo lo siguiente:
- Se debe iniciar cada proceso con un estado no decidido (ni SI, ni NO). En este punto, la red propone una serie de valores determinísticos aplicables al proceso.
- Para compartir los valores, se debe garantizar un medio de comunicación. Esto con el fin de desplegar mensajes de forma segura. El medio, también servirá para comunicar e identificar las partes de forma inequívoca.
- Llegados a este punto, los nodos computan los valores y pasan a un estado decidido (SI o NO). Cada nodo debe generar su propio estado, el cual es parte de un proceso puramente determinístico.
- Una vez decididos, totalizan y gana el estado con mayor cantidad de decisiones a favor.
Estos cuatros puntos definen el funcionamiento básico de un algoritmo tolerante a fallos bizantinos.
Una explicación más cercana
Ciertamente el caso anterior puede ser un poco complejo. Por ello, una explicación más sencilla y aplicada a la blockchain sería:
Imaginemos que Juan realiza una transacción Bitcoin.
Cada nodo en la red, comienza a compilar la transacción en un estado no decidido (TX no confirmada). La confirmación de esa transacción pasa, por un trabajo de minería (nuestro protocolo de consenso). El proceso de minería, verifica que el hash de la transacción sea correcta y lo incluye en un bloque.
Este proceso de verificación es intensivo en cálculo, y sólo es posible por medios determinísticos. Con cada nueva confirmación (estado decidido) de la transacción dada por la mayoría de la red, Juan puede estar seguro de que la transacción ha sido tomada como válida.
Casos de uso de la Tolerancia a Fallas Bizantinas
La Tolerancia a Fallas Bizantinas tiene la capacidad de resolver diversos problemas. Entre estos, hablaremos de algunos de los más relevantes para comprender un poco más su amplia utilidad:
Caso #1: Uso en compiladores de software
Un compilador de código fuente es una de las herramientas informáticas más complejas que podamos conocer. Los compiladores tienen la capacidad de convertir el código fuente de un programa en un binario capaz de ser ejecutado por el computador. Esto significa que convierten algo cercano al lenguaje humano (como C/C++ o Go) en lenguaje máquina o binario.
En medio de todo esto, los compiladores “desgranan” su capacidad en varios sub-programas para poder realizar las siguientes acciones:
- Traducir el código fuente a la arquitectura de procesador deseada. Por ejemplo, podemos decidir si compilar para x86-32 (PC) o ARM (móviles). En este ejemplo, elegimos al x86-32.
- Ajusta los parámetros a las capacidades de la familia o generación del procesador objetivo. Un punto a tener muy en cuenta, pues el código de una generación superior posiblemente no se ejecute en una anterior. En este punto, decidimos hacer código para los Core i3 de 2da Generación.
- Empieza a compilar el código y todos los sub-programas transforman al mismo en código máquina. En paralelo, los subprogramas deciden donde se puede optimizar y qué optimizaciones aplicar al código. El resultado final es nuestro programa ya compilado y listo para ser ejecutado.
En este proceso, la Tolerancia a Fallas Bizantinas es vital, pues garantiza lo siguiente:
- Que los subprogramas apliquen de forma correcta los parámetros y optimizaciones para la arquitectura y generación elegida. De no hacerlo, el resultado final tendrá errores y fallará.
- La aplicación de optimizaciones debe velar porque las mismas no signifiquen la duplicación de datos. Pero la deduplicación a nivel binario tampoco debe afectar al funcionamiento de las partes del binario. En este punto, un análisis de fallas bizantinas es necesario y los compiladores deben ser capaces de analizar esto.
Caso #2: Sistemas de almacenamiento de datos
Otro caso de uso de la tolerancia a fallas bizantinas, se aplica los sistemas de almacenamiento de datos. Muchos sistemas de base de datos e incluso sistemas de archivos lo implementan para mejorar la fiabilidad de los datos almacenados. Un ejemplo de esto, es el sistema de archivos ZFS. Este sistema de archivado es capaz de replicar avanzadas capacidades de hashing, replicación, de-duplicación, corrección de errores, manejo y almacenamiento de grandes cantidades de datos.
Para lograr esto, ZFS hace uso de esquemas de tolerancia a fallas bizantinas para garantizar:
- La no omisión de procesos elementales para el tratamiento de los datos almacenados o por almacenarse en el sistema de archivos. Por ejemplo, la aplicación de hashes a los datos y metadatos, compresión, corrección de errores o de-duplicación de los mismos.
- Que no se realicen pasos indeseables en el procesamiento de datos. Como una de-duplicación que conlleve a la pérdida de datos en el sistema. O una corrección de errores que dañe información.
- Los procesos de creación, lectura y escritura en estructuras anidadas de ZFS usan este tipo de técnicas para garantizar que las mismas sean consistentes en todo momento.
Gracias a todo esto, ZFS mantiene los datos almacenados en su estructura de forma segura. Motivo por el que se le conoce como el sistema de archivos más seguro y avanzado del mundo informático.
Caso #3: Sistemas de aviónica
Este es el caso del Sistema de Manejo de Información de los aviones. Un sistema que funciona en tiempo real y que tiene tolerancia a fallas bizantinas.
Cada uno de los sensores del avión se comunican con los sistemas de mando y control brindando información en tiempo real. La falla de un sensor, no debe significar en ningún momento una falla catastrófica para la aeronave. Para lograr esto, se hace uso de tolerancia a fallas bizantinas. Esto con la finalidad de compensar los datos del sensor o de sistemas dañados y mantener a la aeronave a salvo.
De hecho, en este punto la aplicación de tolerancia a fallos bizantinos es todo un reto. Debido a la cantidad de sistemas y los distintos escenarios a manejar. La aviónica debe tener presente casos como reconfiguración, duplicación, falla de sistemas enteros, y aún así ofrecer resistencia a este tipo de fallos. Si bien la resistencia al 100% es imposible, los ingenieros y programadores hacen un enorme trabajo en este sentido.
Caso #4: Protocolos de consenso blockchain
Los protocolos de consenso en blockchain como PoW son tolerantes a fallos bizantinos. Estos permiten alcanzar a una red distribuida un consenso en condiciones bizantinas. Cuando Satoshi Nakamoto diseñó Bitcoin, tomó en cuenta este tipo de tolerancia. Para ello, creó una serie de reglas y aplicó el protocolo de consenso PoW para crear un software con tolerancia fallos bizantinos. Sin embargo, esta tolerancia no es del 100%.
Pese a ello, PoW ha demostrado ser una de las implementaciones más seguras y confiables para redes de blockchain. En ese sentido, el algoritmo de consenso de prueba de trabajo, diseñado por Satoshi Nakamoto, es considerado por muchos como una de las mejores soluciones para las fallas bizantinas. PoS y DPoS por su parte no son completamente tolerante a fallos bizantinos, razón por la cual suelen complementarse con otras medidas de seguridad.
Ventajas y Desventajas
Ventajas
- Capacidad para garantizar correctitud de datos e información, en sistemas distribuidos. Esto incluso bajo escenarios hostiles para tales tareas.
- Soluciona al problema de procesamiento de información en ambientes heterogéneos.
- Alta eficiencia en términos computacionales y energéticos.
- Ofrece implementaciones que impactan positivamente en la escalabilidad si son bien construidas.
- Mientras más nodos aplicando la tolerancia a fallos bizantinos, más seguro es el modelo.
Desventajas
- La creación de estas soluciones es compleja. Esto puede encerrar otros problemas de seguridad en su implementación.
- Garantizar su correcto funcionamiento requiere de que la distribución del sistema sea creciente. Mientras más nodos aplicando el proceso, más seguro es. Pero esto, también tiene un impacto negativo en la escalabilidad y el ancho de banda de la red.