Ardor Frente a la Competencia, Parte 8: Ethereum (Hinchazón de la Blockchain)

Este artículo forma parte de una serie que pretende comparar Ardor con otros proyectos blockchain con características u objetivos similares. A continuación puedes encontrar las entradas anteriores:

Este artículo continua la comparación iniciada en la entrega anterior entre Ardor y Ethereum. En esta ocasión, se explora como se enfrenta cada plataforma al problema del hinchazón de la blockchain. Para mi sorpresa, ambas plataformas son más similares al respecto de lo que había pensado, aunque también existen diferencias significativas.

Es clave para esta comparación entender cómo está organizada la blockchain de Ethereum.

Estructura de Ethereum

Al igual que Nxt, Ethereum realiza un seguimiento del estado de todas las cuentas con cada bloque nuevo. Y al igual que Bitcoin, Ethereum organiza la información en cada bloque en un arbolo del tipo Merkle (en realidad, en tres de estos árboles) y almacena su hash de raíz en la cabecera del bloque.

¿Cómo funciona esto exactamente? Este diagrama que extraído de este artículo nos ayuda a entenderlo.

 

Las hojas de un árbol Merkle (es decir, las de la parte de abajo) representan todos los datos reales almacenados. Cada nodo por encima de las hojas almacena un hash criptográfico de sus dos hijas. (Nótese que estoy usando el término “nodo” aquí para referirme al elemento del árbol, no a ordenadores en una red. Cada ordenador dela red almacena todo el árbol.)

El diseño tiene la capacidad de que si incluso se cambiase un simple byte de una sola hoja, el hash de su padre también cambiaría, así como el hash del padre de su padre, así sucesivamente hasta el nodo de más arriba, llamado “la raíz Merkle”. En cierta manera, la raíz Merkle contiene un resumen de toda la información de las hojas.

Simplemente agrupando conjuntamente todos las hojas y estableciendo su hash de una sola vez se produciría un resultado similar, pero la estructura de árbol tiene una segunda propiedad interesante, que hace posible demostrar que una hoja particular del árbol está en el árbol sin necesidad de ver todo el árbol. Por ejemplo, en este diagrama es posible demostrar que la transacción realmente ha sido añadida proporcionando para ello información sobre su hermano (en amarillo), su padre (en gris) y los otros hermanos y padres hasta su camino de vuelta a la raíz. Otro usuario podría calcular los hashes relevantes en cada nivel del árbol y a continuación comparar la raíz de Merkle resultante con la que está almacenada en la blockchain. Estas “pruebas de Merkle” son la base del sistema de los clientes de verificación de pagos simplificados en Bitcoin (SPV) y también de diversas propuestas de escalado para Ethereum.

Ethereum utiliza tres árboles de Merkle separados para almacenar la información de cada bloque: uno para las transacciones de los bloques; un segundo para una serie de “receptores” de esas transacciones, los cuales representan los efectos de cada transacción; y una tercera para almacenar el estado instantáneo de cada cuenta, incluyendo sus saldos y datos asociados. Almacenar el estado completo del sistema en cada bloque aparenta ser un terrible derroche, pero puesto que cada bloque solo modifica una pequeña porción de hojas, la mayoría de las ramas del árbol de estado no cambian de bloque a bloque y cada nuevo árbol de estado puede hacer referencia a ramas completas del estado anterior con un coste mínimo. Hay unas pocas complicaciones técnicas sobre este enfoque, y es por ese motivo por el que Ethereum en realidad usa una estructura de datos ligeramente diferente llamada árbol Merkle-Patricia, pero el concepto sigue siendo el mismo.

Los Nodos de Rápida Sincronización de Ethereum

El hecho más importante de todo esto es que las propiedades de las funciones de hashes criptográficos aseguran que sea prácticamente imposible construir dos árboles diferentes con la misma raíz. Como resultado, el registro de la raíz Merkle almacenado en la cabecera del bloque en Ethereum es suficiente para establecer que la red validó en ese momento la correspondiente transacción y estado de transacciones.

En otras palabras, incluso aún después de que un nodo haya “olvidado” los contenidos de un bloque antiguo, mientras siga conservando las (mucho más pequeños) cabeceras del bloque en el archivo, puede solicitarle a un nodo completo el contenido completo de un bloque y verificar por si mismo que el nodo completo no ha sido adulterado con ningún dato. (Hay que recordar que  aquí y para el resto del artículo vuelvo a referirme a un “nodo” como a un par en la red, no un objeto del árbol de Merkle.)

Este enfoque es el que se utiliza la opción de sincronización rápida del monedero Go Ethereum (geth). Para realizar una sincronización rápida, un nuevo nodo primero descarga y verifica todas las cabeceras de los bloques, empezando por el bloque génesis (en realidad, solo uno de cada 100 cabeceras de bloque debe ser verificada; ver el enlace en GitHub para más detalles). Puesto que las cabeceras continúan la Prueba de Trabajo, este paso es suficiente para mostrar que la red alcanzó un consenso sobre la raíz de Merkle en cada cabecera en el momento en que el bloque fue minado.

En algún punto del pasado reciente, supongamos que hace 1024 bloques, el nodo recibe una versión completa del estado del árbol proveniente de sus pares y la valida frente a la raíz Merkle en su correspondiente cabecera. Desde ese punto en adelante, el nodo descarga los bloques completos desde los pares y re-ejecuta todas las transacciones hasta que alcanza el bloque más reciente, en cuyo punto simplemente se convierte en un nodo completo ordinario.

Aunque Go Ethereum actualmente no lo soporta, es también posible que los nodos poden continuamente el árbol de estado según avanza el tiempo, manteniendo al mínimo la cantidad de datos de estado que deben ser almacenados.

El Podado de las Child Chains en Ardor

Si has analizado el arquitectura de Ardor de cadena madre / cadena hija (parent chain / child chain), esta estrategia posiblemente te resulte bastante familiar. Ardor toma un enfoque muy similar respecto a sus child chains.

En pocas palabras, la plataforma Ardor consiste en un única cadena madre del tipo Prueba de Participación (proof-of-stake), también conocida como Ardor, y una serie de child chains. La cadena madre soporta solo unos pocos de tipos de transacciones, básicamente aquellos requeridos para transferir Ardor y para la forja. Las child chains, por su lado, manejan todo el negocio real que tiene lugar en la plataforma usando las transacciones inteligentes que describí en el artículo previo de esta serie.

Solo la moneda de la cadena madre (ARDR) se puede usar para forjar. Las transacciones que involucran tan solo a las monedas de las child chains no afectan los saldos de la moneda de forja, así que no son esenciales para la seguridad de la blockchain y no necesitan ser almacenadas permanentemente. Los nodos “agrupadores” especiales en cada child chain recolectan esas transacciones, las agrupan juntas, establecen su hash, y envían ese hash a la red usando un tipo de transacción especial llamado ChildChainBlock. Incluyen toda la información de la transacción junto a la transacción del tipo ChildChainBlock, así que los forjadores y resto de nodos pueden verificar que las transacciones de la child chain son válidas y producen realmente el hash indicado, pero los datos en sí mismos no son almacenados en la blockchain y tras un tiempo establecido se pueden podar. Todo lo que queda en la cadena madre es el hash de esa información.

Opcionalmente, los nodos especiales de archivo en cada cadena hija pueden almacenar el historial completo de las transacciones de esa child chain. En los casos en que el historial sea necesario, los nodos pueden obtenerlo, calcular el hash de de las transacciones de agrupación originales y verificar que los hashes se corresponden con los que están almacenados en la blockchain.

Llegados a este punto, espero que la comparación con la opción de sincronizado rápido de geth haya quedado clara: en ambos casos, los nodos no necesitan almacenar la gran mayoría de los datos de la transacción para ser capaces de verificar que la red aprobó todas esas transacciones en el momento en que fueron hechas. En Ethereum, es suficiente con verificar la prueba de trabajo en la cabecera de los bloques y la exactitud de una raíz Merkle determinada para ser capaz de confiar en el correspondiente árbol de estado. Ardor es ligeramente más complicado porque usa el algoritmo de prueba de participación para el consenso, pero almacenar todo el historial de transacciones de ARDR junto a las transacciones ChildChainBlock asegura que los nodos pueden verificar, desde el bloque génesis, que cada bloque fue forjado por un forjador legítimo.

Comparando Ambos Diseños

Llegados a este punto, espero que estés de acuerdo conmigo en que podemos establecer los siguientes paralelismos entre Ethereum y Ardor:

  • Un nodo completo de Ethereum es similar a un nodo de Ardor que almacena el historial completo de cada child chain.
  • Un nodo de sincronización rápida de Ethereum que pode de manera continua el árbol de estado es similar a un nodo ordinario de Ardor, el cual almacena toda la cadena madre pero poda todos los datos de la cadena hija.
  • Ardor ofrece la posibilidad de ejecutar un nodo que almacene toda la cadena madre, además de los datos de las transacciones almacenadas de una sola child chain. Esta opción no tiene equivalente en Ethereum.

Por supuesto que estas analogías no son perfectas. En concreto, no hay que pasar por alto que las cabeceras de los bloques de Ethereum son considerablemente más pequeñas que los bloques completos de la cadena madre de Ardor. También he pasado por alto el mecanismo que Ardor utiliza para realizar el seguimiento de las instantáneas del estado completo del sistema y almacenar los hashes de esas capturas en la cadena madre.

Aún así, creo que la comparación es de ayuda. El tercer elemento de esta lista es especialmente interesante puesto que parece constituir la mayor diferencia cuantitativa entre ambos diseños. En Ardor, la capacidad para almacenar el historial de las transacciones de cada child chain en un juego de nodos de archivo diferenciado permite un tipo de partición vertical de la base de datos de la partición. Puesto que es probable que cada child chain sirva a diferentes negocios o proyectos, particionar el juego completo de transacciones por las líneas establecidas por las child chains parece una evolución natural. Quizás en Ethereum la mejora analogía sería un diseño dónde el usuario pudiese ejecutar un nodo completo para un único proyecto, como Golem, sin tener que ejecutar simultáneamente nodos para Augur, BAT o cientos de otros proyectos.

Sobre esto último, me llama la atención que los árboles Merkle de Ethereum puedan acomodar de manera natural ese diseño, dónde un “nodo completo de Golem” rastrearía toda la blockchain en búsqueda de todas las transacciones que involucrasen GNT, almacenaría todas las pruebas Merkle para esas transacciones y transiciones de estado permanentemente y descartaría los datos restantes. Tengo que admitir que no he pensado suficientemente sobre las implicaciones de esta idea, así que no voy a decir mucho más sobre ello.

En cualquier caso, ni esta hipotética estrategia para Ethereum, ni la arquitectura de cadena madre / cadena hija de Ardor, implica una fragmentación real de la blockchain, puesto que en ambos casos cada nodo todavía tiene que procesar todas las transacciones de toda la red. Estos diseño particionan el almacenamiento pero no el ancho de banda o el poder de computación requerido para ejecutar la blockchain. Una adecuada estrategia de escalado debería dirigir estos tres cuellos de botella.

Hablando de fragmentación…

Fragmentación

La visión de Ethereum para el escalado de la cadena a largo plazo es la fragmentación, una manera de particionar tanto el almacenamiento, los datos y el procesado de las transacciones. El objetivo es que la mayoría de los nodos de la red tengan que procesar las transacciones de un único fragmento, liberándolos de la carga de tener que validar y almacenar las transacciones que afecta a otros fragmentos.

Ni siquiera voy a tratar de evaluar las propuestas del equipo de Ethereum aquí, puesto que este artículo ya se está extendiendo demasiado, pero si estás interesado en este tema os recomiendo visitar su fantástico documento con Preguntas y Respuestas sobre fragmentación en GitHub.

Sin embargo, la razón por la que he sacado ha relucir la fragmentación es que los desarrolladores de Ardor han sugerido que están explorando maneras de llevar el procesado de las transacciones de las child chains a redes dedicadas dentro de la red Ardor. No nos han ofrecido datos técnicos todavía, y voy a evitar especular aquí sobre la manera en que podrían funcionar pero, personalmente, la idea me parece realizable.

Si los desarrolladores pudieran ofrecer más sobre esta idea, entonces la plataforma Ardor se parecería mucho al “diseño básico de una blockchain fragmentada”, descrita en el documento del equipo de Ethereum. Esa sección del documento describe una serie de nodos “ordenadores” (agrupadores) encargados de recolectar (agrupar) las transacciones de un único fragmento (child chain), validándolos y almacenando su hash en una “cabecera de ordenación” (transacción del tipo ChildChainBlock) en la cadena madre. Los “super nodos completos” (actuales nodos de la cadena madre) procesarían todas las transacciones de todos los fragmentos; los “nodos top-level” (los futuros nodos de la cadena madre) procesarían solo los bloques de la cadena madre, pero no todos los datos de todas las ordenaciones; y los “nodos de un solo fragmento (los futuros nodos de las child chain) procesarían todas las transacciones en la cadena madre y un único fragmento.

Casi todas las complicaciones surge de la comunicación entre fragmentos y, como resultado, este diseño funciona mejor cuanto más independientes son los fragmentos. Como ya he mencionado, las child chains de Ardor pueden cumplir naturalmente este tipo de partición, dónde cada cadena soportará un proyecto separado, dónde las interacciones entre proyectos están permitidas pero son menos comunes que las transacciones dentro de un proyecto.

Conclusión

En estas fases tempranas, estas ideas son inciertas, claro está. Sin embargo, las posibilidades son emocionantes. El diseño de Ardor ya incorpora el algoritmo de consenso de Prueba de Participación, un objetivo separado que el equipo de Ethereum se ha establecido para si mismo, además de una partición razonable de los datos de la blockchain, lo cual es un requerimiento obvio para cualquier solución fragmentada. Entre las ausencias notables en Ardor encontramos las pruebas Merkle, u otras maneras compactas de que las particiones se comuniquen información de estado entre ellas, pero no parece que estas características pudieran ser introducidas en la plataforma a través de un hard fork. Los hashes del snapshot y los hashes de los bloques child chain que se convertirían raíces Merkle ya están presentes en el protocolo, después de todo.

Pero ¿qué podemos decir sobre el estado actual de ambos proyectos? Quizá el hecho más interesante que he descubierto al investigar y escribir este artículo es que Ethereum realmente escala mucho mejor de lo que yo había pensado. La opción de sincronización rápida de Go Ethereum para los nodos completos permite algunas de las ventajas del diseño de Ardor, y si algún día incorpora el podado del estado del árbol la analogía será incluso más cercana.

Por otro lado, el mayor inconveniente del actual diseño de Ethereum es que todavía tiene que haber nodos completos en algún lugar de la red, y esos nodos completos tienen que almacenar más de 300 GB de la blockchain de Ethereum. Conforme sigue creciendo, y en consecuencia, los costes de ejecutar un nodo completo crecen a la par, uno esperaría que la proporción de nodos completos en relación a los nodos ligeros y nodos de sincronización rápida descienda. Como consecuencia, cada nodo completo probablemente acabaría teniendo que gestionar un mayor volumen de solicitudes de otros nodos, mayor incremento de los costes (en términos de ancho de banda y poder computacional) para ejecutar un nodo completo.

Incluso sin fragmentación, el diseño de Ardor mitiga este problema potencial al romper los monolíticos nodos completos de Ethereum en juegos de nodos de archivo, cada uno de los cuales almacenaría solo el estado de una child chain. Sería posible almacenar el historial de varios nodos simultáneamente si así se desease, pero unos pocos nodos, o potencialmente ninguno de ellos, serían requeridos para restaurar el historial completo del ecosistema completo

No es necesario decir que escalar una blockchain es una ardua tarea. Más allá de los diversos proyectos que he analizado para esta serie, Ardor y Ethereum me parece que ofrecen la visión más convincente para el escalado de una cadena. Y mientras espero que ambas triunfen, tengo que admitir, juzgando únicamente por el progreso concreto que cada proyecto ya ha hecho hacia conseguir su objetivo, Ardor me parece que parte de una situación ventajosa.


Prueba Ardor en la testnet

Acerca de la última versión de Ardor para la testnet

 

 

View this in: English 简体中文

Deja un comentario