Hacia una mayor escalabilidad en la cadena con la Unitrie
RSK se creó en 2015 como una cadena lateral compatible con Ethereum. En 2016, cuando la cadena lateral RSK todavía estaba en desarrollo, decidimos mejorar y simplificar su diseño mediante el reemplazo de uno de los componentes clave de Ethereum: el trie de cuentas, también llamado trie de “estado mundial” en el documento de especificación técnica de Ethereum. El trie de estado mundial es la base de datos principal de las blockchains similares a Ethereum, y la estructura de datos sobre la que se apoya se llama “trie Patricia seguro modificado”. Diseñamos una estructura de datos de estado de reemplazo que evolucionó hasta convertirse en lo que ahora llamamos Unitrie.
Sergio Lerner (RSK Labs) presenta el Unitrie en laBitConf (2016)
Algunas de las propiedades del Unitrie (original) son las siguientes:
- El árbol de base 16 se reemplazó con un árbol de base 2 (binario).
- En las celdas de almacenamiento pueden almacenarse valores de longitud arbitraria.
- Todos los tries son combinados y combinan celdas de almacenamiento de contratos con celdas de cuentas para formar una estructura de datos más grande llamada Unitrie.
- Los enlaces se aumentan con marcas de tiempo de la actualización más reciente (el campo “lastUpdateTimestamp”) y, como consecuencia, el Unitrie admite el alquiler de almacenamiento y la hibernación automática de nodos.
- Los prefijos se almacenan en el nodo primario, para cada uno de sus nodos secundarios. Esto hace posible eliminar nodos hoja por hibernación con el fin de maximizar la supresión de datos. Además, esto previene el efecto secundario de lectura de otros nodos en el procesamiento de transacciones paralelas.
- Las claves están protegidas por un prefijo de hash de 10 bytes (80 bits) con la finalidad de prevenir el desequilibrio del trie, pero de todas maneras contienen la clave entera (preimagen de hash) después del prefijo con hash.
- Los nodos almacenan el tamaño de su carga.
- Los nodos almacenan la cantidad de bytes que consume su subárbol.
- Si un nodo es demasiado pequeño para almacenarlo por sí mismo en la base de datos, se lo incrusta en su nodo primario. Esto ahorra el resumen de hash de 32 bytes que se utiliza para hacer referencia al nodo.
Algunas de las ventajas del Unitrie son evidentes, pero otras son sutiles. La siguiente es una lista de las mejoras principales:
- Simplificación del diseño general.
- Reducción de la complejidad de las implementaciones y, por lo tanto, una reducción de riesgo de errores de consenso.
- Simplificación del diseño de los clientes ligeros (lightweight).
- Reducción del tiempo de la sincronización de estado (también conocida como sincronización rápida/sincronización warp) al hacerlo más paralelizable y resistente a proveedores de estado maliciosos.
- Posibilidad de pruebas de fraude más simples para clientes SPV y puentes SPV.
- Posibilidad de recolección más simple de la basura de estado.
- Posibilidad de alquilar contratos por celda de almacenamiento.
- Posibilidad de hibernación y reactivación por celda de almacenamiento.
- Posibilidad de ejecución paralela con detección de colisiones por celda de almacenamiento.
- Posibilidad de hacer consultas EXTCODESIZE rápidas sin necesidad de recuperar datos de código.
RSK Labs propuso el diseño del Unitrie para la RSK blockchain e hizo una breve presentación de él en laBitConf, que se celebró el 4 y 5 de noviembre de 2016. Sin embargo, nuestra prioridad principal en ese momento, cuando todavía no se había lanzado la mainnet de RSK, era mantener una mayor compatibilidad con las herramientas de desarrollo de Ethereum, así que decidimos posponer la implementación del Unitrie y solo aplicamos dos modificaciones críticas a su estructura de datos: el uso de base 2 en lugar de base 16, y el almacenamiento de valores de longitud arbitraria. El uso de base 2 haría posible la futura migración al Unitrie mediante una conversión dinámica del trie, en lugar de una migración de toda la base de datos. Esa resultó ser una sabia decisión, ya que ahora estamos probando la migración rápida de toda la estructura de árbol dinámicamente, preservando la mayoría de las partes estructurales.
A fines de 2017, nos sorprendió ver que Vitalik proponía un cambio similar para Ethereum en los foros de Ethereum. También destacó las ventajas de contar con un árbol de estado combinado. Ello respaldaba nuestra tesis inicial de que la unificación de los tries era un diseño mucho mejor.
La propuesta de Vitalik de trie de estado combinado (2017)
La hora ha llegado
En enero de 2019, la RSK blockchain cumplió su primer año, y fue un año con 100 % de tiempo en actividad, por lo tanto, decidimos renovar nuestros esfuerzos de impulsar la adopción de la estructura de datos Unitrie en una actualización de red posterior. Modificamos y perfeccionamos propuestas de mejora de RSK (RSKIP) y creamos nuevas RSKIP e implementaciones de referencia. Este artículo forma parte de nuestro intento de comunicar cómo se beneficiaría la comunidad de RSK con este cambio propuesto. Actualizamos RSKIP16 y agregamos RSKIP107, RSKIP108 y RSKIP109. RSKIP107 describe cómo se comprimen y almacenan los nodos de trie. RSKIP108 describe cómo se asignan a claves de tries las direcciones de cuentas y las direcciones de celdas de almacenamiento. RSKIP109 redefine los costos de escritura de celdas de almacenamiento para incentivar el uso de direcciones de almacenamiento más cortas. También implementamos y probamos todo junto, y observamos mejoras perceptibles en el rendimiento de los nodos y el consumo de memoria, desde las actualizaciones de estado hasta la sincronización. Sin embargo, no todo se desarrolló sin inconvenientes durante las pruebas. Por ejemplo, decidimos excluir la propuesta de mover los prefijos de nodos de trie a los nodos primarios. La razón fue que este cambio complica la conversión rápida entre tries nuevos y viejos que depende de la similitud de las similitudes de las estructuras de árbol.
Para reducir el riesgo asociado con las bifurcaciones duras, creemos que la mejor estrategia es dividir los cambios en dos actualizaciones de red consecutivas. La primera, en el segundo trimestre de 2019, incluiría Unitrie, claves protegidas con prefijo, caché de tamaño de carga, caché de tamaños de árbol y compresión de nodos en disco. La segunda, en el cuarto trimestre de 2019, incluiría las marcas de tiempo de la actualización más reciente del alquiler de almacenamiento. Optamos por posponer las funcionalidades relacionadas con el alquiler de almacenamiento porque la RSKIP relativa a ese tema todavía no es definitiva y porque los cambios de la segunda actualización de la red solo afectan a los nuevos nodos de trie creados (no requiere la migración del trie), mientras que la primera requiere la migración completa del trie.
Una actualización de red única en su tipo
La combinación total de nodos de almacenamiento y cuentas en un único árbol solo puede efectuarse mediante bifurcación dura, lo cual significa que la mayoría de los mineros necesitan hacer la actualización para admitir este cambio y todos los nodos completos también deberían actualizarse a fin de mantenerse sincronizados. Sin embargo, la actualización del Unitrie no implica ninguna modificación importante a la economía de la plataforma. Se aplicará una ligera reducción en el costo de almacenamiento, que se debe a una mejor correspondencia entre el costo real de almacenamiento y los montos cobrados. Este cambio beneficiará a todos los actores de la comunidad. Además, los cambios no afectan la seguridad ni la privacidad de la plataforma. Hay que tener presente que la mayoría de las herramientas de desarrollo y las wallets no acceden de manera directa a los datos internos del estado mundial, por lo tanto, no se ven afectadas por esta bifurcación dura.
El aspecto negativo del mecanismo de actualización es que la vieja base de datos de estado de nodos completos ya no será compatible con la nueva base de datos. Crear un nodo completo que sea compatible con el viejo trie y también con el nuevo es una tarea abrumadora, con escasos beneficios. La buena noticia es que, debido a la gran cantidad de mejoras de rendimiento, la nueva sincronización completa solo durará una fracción de lo que habría durado antes. Además, hemos hecho pruebas de migración de la base de datos de estado al nuevo formato en el inicio de los nodos, de modo que los nodos pudieran mantener un tiempo de actividad casi ininterrumpido después de la actualización de software.
El Unitrie
El Unitrie combina información de cuentas con las celdas de almacenamiento de todos los contratos. Almacena las celdas de almacenamiento de contratos como hojas de un subárbol con raíz en el nodo correspondiente a la dirección de almacenamiento del contrato. Además, reparte la información de contrato en varios subnodos distintos del árbol. El siguiente diagrama simplificado muestra una cuenta (controlada por ECDSA) que no tiene ningún nodo secundario, un contrato que tiene un nodo secundario que almacena el código del contrato, y un subárbol secundario que contiene las celdas de almacenamiento en sí.
Ejemplo de Unitrie de un estado de blockchain
La combinación de cuentas y almacenamiento de contratos no es la única diferencia; la asignación de claves también cambia. Repasemos cómo funciona el trie de cuentas de Ethereum: para proteger el trie, se utiliza el resumen de hash de la dirección de la cuenta como clave para recuperar un valor. Los nodos del trie no se ordenan por dirección de cuenta, sino por su resumen de hash. Esta transformación esencial no se realiza para impedir que alguien efectúe un ataque de spam contra la estructura de datos con valores que compartan prefijos de clave crecientes que degenerarían el árbol hasta convertirlo en una cadena larga. Un ataque así podría forzar a un nodo completo a realizar ciertas búsquedas con mucha mayor lentitud o a aumentar el tamaño de ciertas pruebas de inclusión de trie. En el Unitrie, las claves se forman a partir de un prefijo de resumen de hash de 80 bits, seguido de la dirección normal completa de la cuenta. Solo se emplean 80 bits para propagar las claves por el trie y mantenerlo probabilísticamente equilibrado. Dado que el efecto del ataque de degeneración del árbol es mínimo, 80 bits son más que suficiente como disuasivo. Para dicho ataque sería necesario diseñar un hardware especial de fuerza bruta para prefijo de hash basado en ASIC, que sea muy similar a un minero de prueba de trabajo, y construir millones de esas cajas de “minería”. Si imaginamos que las máquinas de Bitcoin de última generación pudiesen realizar una búsqueda arbitraria por preimagen de prefijos de 80 bits, entonces el atacante debería gastar unos seis millones de dólares estadounidenses en electricidad para buscar colisiones en las 80 diferentes posiciones de 80 bits con el fin de degenerar ligeramente el trie. Aun así, el efecto en el tiempo de procesamiento de bloques sería despreciable (debido a los cachés) y la prueba de inclusión de las cuentas desequilibradas aumentaría de tamaño apenas 2 Kb.
Una ventaja de esta nueva asignación es que preserva la dirección de la cuenta y las direcciones de las celdas de almacenamiento en el estado, lo cual permite que muchas aplicaciones de recolección de datos presenten al usuario información valiosa sin necesidad de indexar toda la b. El siguiente diagrama describe la transformación de las direcciones de cuenta y de almacenamiento en una clave de trie:
Transformación de las direcciones de cuenta y de almacenamiento en una clave de trie
Para presentar el panorama completo, mostramos cómo se asigna al Unitrie cada tipo de datos:
Clave | Valor | Descripción |
0x00
SHA3(account_addr)[0:9] account_addr |
Rlp (nonce, cantidad, indicadores) | estado de cuenta |
0x00
SHA3(account_addr)[0:9] account_addr 0x80 |
matriz de bytes | código de cuenta |
0x00
SHA3(account_addr)[0:9] account_addr 0x00 |
0x00 | marcador de posición para aislar el árbol de almacenamiento |
0x00
SHA3(account_addr)[0:9] account_addr 0x00 SHA3(storage_address)[0..9] trimmed_storage_address |
matriz de bytes | valor en la celda de almacenamiento |
El primer byte nulo se usa para almacenar este árbol en un espacio de nombres especial. Esto permite realizar mejoras futuras para utilizar otros espacios de nombres sin que haya riesgo de colisión. Algunas de las posibles mejoras futuras que podrían consumir sus propios espacios de nombres son:
- almacenar un nodo especial que se expanda a un árbol (o bosque) de todos los hashes de bloque anteriores para posibilitar las pruebas de prueba de trabajo (NiPowPow) y las listas de omisión;
- hacer referencia a direcciones de cuentas con claves de mayor longitud (p. ej., 256 bits) para que la seguridad sea mayor;
- hacer referencia a direcciones de cuentas mediante el uso de direcciones de dos hashes, según se define en RSKIP32.
Hay muchas diferencias entre el Unitrie de RSKIP16 y la propuesta de Vitalik. Una de ellas es que el Unitrie no almacena el nonce y la cantidad en diferentes nodos, sino que los mantiene juntos. Eso se debe a varias razones:
- La serialización y deserialización de esos dos campos tardan poco, por lo tanto, una mayor división hace perder eficiencia debido al aumento de los accesos al disco para recuperar el estado de la cuenta.
- Es preferible tener cierta cantidad de datos en la dirección específica del contrato para poder hacer un seguimiento de los cambios del contrato en el futuro.
- Las cuentas pueden usarse para enviar “spam” al trie, por eso es importante reducir el espacio que consumen las cuentas.
El panorama de la Unitrie RSKIP
La Unitrie está definida por 9 RSKIPs (Propuestas de mejoras de RSK). Cada RSKIP describe un componente específico del Unitrie: la estructura, el almacenamiento, el mapeo de claves, la renta del almacenamiento, hibernación y costos del combustible. El siguiente diagrama representa esta separación:
Los RSKIPs relativos al Unitrie
En la primera actualización de la red, solo 4 de los RSKIPs podrán ser implementados, y los restantes serán implementados en la siguiente actualización de la red. Esto asegura la minimización de los riesgos de migración.
Qué quedó fuera del Unitrie
Durante el debate original sobre la Unitrie, concluimos que separar el prefijo de los datos del nodo en dos nodos diferentes ayudaría a mantener la inmutabilidad total de ramas del árbol intactas, y permitir una paralelización más detallada de tres actualizaciones. Llamamos a este esquema trie PDB porque los nodos pueden ser de uno de tres tipos disjuntos: prefijo, datos o rama (branch). Como el cambio a un árbol PDB requiere de profundos cambios estructurales, quedó fuera de la propuesta del Unitrie. Sin embargo, el árbol PDB podría ser tema de futuras investigaciones.
Ejemplo de árbol PDB usado para almacenar el estado de la blockchain
Ahora analizaremos más en detalle cada una de las ventajas del Unitrie de RSK.
Pruebas de membresía más cortas
Al usar un trie binario, en lugar de uno en base 16, las pruebas de membresía de las cuentas del trie de RSK son lo más breves posible, mientras que el tiempo necesario para validar sus pruebas de membresía es cercano a óptimo. Esto posibilita que haya nodos ligeros descentralizados, la ejecución de teléfonos móviles y un menor consumo de energía y ancho de banda. En el siguiente diagrama de ejemplo, el trie de base 16 requiere de 30 punteros (anillos) y 3 nodos (círculos) para probar la existencia de un nodo objetivo (círculo azul). El trie de base 2 solo necesita 8 punteros y 8 nodos. Cuando se los transmite, los nodos no requieren que se transmitan las referencias primarias, porque sus referencias pueden calcularse dinámicamente, y por consiguiente, la prueba del trie binario requiere un 26 % del espacio que la del trie de base 16.
Comparación entre pruebas de membresía de trie de base 16 y de base 2
Reducción del tamaño del estado mediante la compresión de nodos de cuentas
Las cuentas que están en el Unitrie no necesitan almacenar el resumen de hash de la raíz del trie de “almacenamiento” ni el resumen de hash del código, y esto significa que se eliminan del estado casi un 60 % de los datos de la cuenta. Por ejemplo, una cuenta que almacena 1 RBTC consume unos 38 bytes en lugar de los 104 bytes que consume en Ethereum. El diagrama siguiente muestra el ahorro aproximado de espacio que se logra por eliminar campos innecesarios.
Compresión de nodos de cuenta por eliminación de campos innecesarios
Reducción del tamaño del estado mediante la incrustación de nodos pequeños
En el caso de los nodos secundarios cuyo tamaño es menor de ~44 bytes (valor exacto por determinar), el Unitrie brinda la posibilidad de incrustarlos directamente en nodos primarios. Esa funcionalidad se describe en la RSKIP107. Como la mayoría de las cuentas terminan teniendo nodos de entre 31 y 41 bytes de tamaño, la mayoría de las cuentas se incrustarán en nodos primarios. Esto reduce la sobrecarga de cuentas en 62 %. La reducción del tamaño de las cuentas que permite lograr la incrustación en combinación con el acortamiento de los registros de cuentas llega al 81 %, y no solo reduce el tiempo para sincronizar y los requisitos de recursos de los nodos completos, sino que también reduce el riesgo de ataques de DoS por envío de spam al estado con creaciones de cuentas. El siguiente diagrama de ejemplo muestra cómo un nodo que tiene dos nodos secundarios en el trie de Ethereum se convierte en el Unitrie en un solo nodo con su nodo secundario incrustado.
Incrustar dos nodos pequeños en su nodo primario
Reducción del tamaño del estado y un menor costo del combustible mediante la compresión de claves de celdas de almacenamiento
Nuestra RSKIP108 describe cómo pueden comprimirse las celdas de almacenamiento cuando las claves de almacenamiento tienen prefijos largos de ceros. Las celdas que tienen direcciones de un solo byte y almacenan un único byte pueden comprimirse hasta alcanzar un 10 % del tamaño sin comprimir, porque su poco tamaño también hace posible la incrustación de nodos. Para incentivar a los usuarios a utilizar el almacenamiento comprimido, RSKIP109 actualiza el costo de operaciones de escritura en el almacenamiento de contratos. Por ejemplo, almacenar 0x01 en la dirección 0x00 consumiría hasta un mínimo de 5460 unidades de combustible, en lugar de las 20.000 que consume en Ethereum. El siguiente diagrama describe las diferentes claves que se utilizan en Ethereum y en el Unitrie para la dirección de celda de almacenamiento 0x01.
Ejemplo de compresión de clave de almacenamiento
Mayor escalabilidad cuando se lo combina con procesamiento paralelo de transacciones
Nuestra RSKIP04 propone el procesamiento paralelo de transacciones con el fin de reducir el tiempo de procesamiento de bloques. Al reducir el tiempo de procesamiento de bloques, podemos propagar los bloques más rápido y mejorar el consenso. También significa que podemos poner más transacciones en los bloques sin retrasar la propagación de los bloques. En general, la mayor latencia de propagación de bloques beneficia a los grupos de minería más grandes por sobre los más pequeños, por eso el saber que hacemos un escalamiento sin reducir la descentralización es algo tranquilizador. Sin embargo, la blockchain solo puede beneficiarse del procesamiento paralelo de transacciones si estas pueden dividirse en conjuntos no superpuestos en términos de acceso a estados de contratos. Si todas las transacciones llaman a un único contrato de token, entonces ese contrato fuerza la serialización de las transacciones y se convierte en el cuello de botella. Una solución, especificada en RSKIP59, es diseñar contratos de manera que las celdas de almacenamiento de contratos se transfieran a los subcontratos, lo cual crea relaciones primario-secundario. Entonces, los saldos de token de diferentes usuarios se almacenan en diferentes contratos. De todos modos, la solución requiere rediseñar y volver a implementar los contratos para forzar el uso de patrones de diseño particulares que posibiliten la escalabilidad. Sin embargo, el Unitrie podría resolver el problema sin el obstáculo asociado de usar nuevos patrones. El Unitrie permite simplificar la detección de accesos simultáneos a celdas de almacenamiento, en lugar de detectar accesos simultáneos a contratos enteros. Esto significa que siempre y cuando dos transacciones no escriban las mismas celdas de almacenamiento (o una lea una celda que la otra ha escrito), ambas pueden ejecutarse simultáneamente. Por ejemplo, los contratos ERC20 por lo general solo cambian celdas relacionadas con las cuentas de origen y destino, por ende, esos contratos recibirían capacidad de paralelización inmediata con detección a nivel de celda. Si bien podría lograrse la misma funcionalidad sin el Unitrie, este simplifica muchísimo el algoritmo de detección de colisiones de escritura. Como ejemplo, el diagrama siguiente describe dos hilos que procesan transacciones. El primer hilo modifica una celda de un contrato C (indicada por la flecha violeta) que el hilo 2 no afecta. El segundo hilo, a su vez, modifica otras dos celdas del mismo contrato, lo cual no afecta a la celda modificada por el primer hilo.
Dos hilos de ejecución que modifican el mismo almacenamiento de contrato
Mayor equidad cuando se lo combina con alquiler de almacenamiento
Una consecuencia del diseño de Ethereum es que permite el arbitraje de combustible, mediante el cual los usuarios pueden comprar por anticipado y ocupar celdas de almacenamiento sin almacenar ningún dato útil, solo para vaciarlas después con el fin de recuperar parte del combustible utilizado para comprarlas en primer lugar y vender ese combustible a terceros. Otra consecuencia no intencional es que Ethereum pide un pago por adelantado elevado para usar nuevas celdas de almacenamiento, ya que este pago es para el almacenamiento perpetuo y la garantía de ejecución del par clave/valor.
El alquiler de almacenamiento mitiga ambos problemas. La forma más analizada y aceptada de alquiler de almacenamiento exige que los usuarios que interactúan con un contrato paguen una tarifa proporcional al tiempo que dicho contrato estuvo inactivo y proporcional al espacio de memoria consumido por el contrato durante el tiempo de inactividad. La RSKIP61 propone el uso de alquiler de contratos para evitar algunas consecuencias indeseadas del diseño original de EVM que afecta la equidad de las plataformas. Si bien esto proporciona equidad probabilística, es un modelo poco preciso y no funciona bien en casos extremos. Un contrato de propiedad colectiva que almacena millones de pares clave/valor, pero que rara vez se utiliza, pondría una carga excesiva de alquiler de almacenamiento en el primer usuario que lo llame después de un período de inactividad prolongado. El Unitrie simplifica la tarea de rastrear las fechas y horas de acceso más reciente de celdas de almacenamiento de modo que el alquiler de almacenamiento se vuelva más preciso, lo cual haría posible que un contrato pague alquiler solo por las celdas que participen en la ejecución de la llamada. La simplificación, especificada en RSKIP113, es consecuencia de tratar a todos los nodos por igual, de manera que la cuenta, el código y las celdas de almacenamiento puedan consumir alquiler cuando se acceda a ellos.
Aumento de la integridad con recolección simplificada de basura de estado
La recolección de basura de estado es la eliminación de datos de estado viejos a los que nunca más se hará referencia en condiciones normales porque se los ha sobrescrito. En casos excepcionales, tales como una reorganización considerable de la blockchain, es posible recalcular esos datos mediante la reejecución de bloques viejos a partir de un punto de control de estado calculado con anterioridad. Sin embargo, la recolección de basura en Ethereum no es trivial, porque debe aplicarse a muchas bases de datos (o tries) separadas, una por cada contrato activo. Usar el Unitrie significa que la recolección de basura se aplica a una sola base de datos, lo cual reduce el riesgo de interrupciones del hilo que podrían alterar la base de datos durante la recolección de basura y dejarla en un estado incoherente.
Sincronización de estado más rápida y simple
Hay muchas aplicaciones que necesitan consultar el estado de la blockchain a una altura de bloque en particular, desde las wallets ligeras hasta los puentes de blockchain. Por la estructura binaria del Unitrie, el consumo de espacio es mínimo y se maximiza el rendimiento para la recuperación y las pruebas de membresía de los datos del estado. También reduce la complejidad de los comandos de red usados en la transmisión de información de estado.
Sin embargo, lo más importante es que el Untrie permite la descarga rápida y en paralelo de información de estado para realizar una sincronización rápida o una sincronización warp. Los nodos pueden recuperar información de estado con mayor eficiencia si toda la información está almacenada en un solo trie. Como el Unitrie almacena la cantidad de bytes que consume el subárbol que tiene raíz en cada nodo, la estructura de datos del Unitrie admite consultas de rango de tamaño. Los pares pueden usar esa funcionalidad para solicitar “paquetes” de trie de un tamaño en particular, a partir de cualquier desplazamiento de bytes. En consecuencia, las solicitudes pueden paralelizarse de manera bien equilibrada. Por ejemplo, un nodo puede recolectar información de estado de 10 nodos y solicitar un rango de bytes de 0 a 100 K para el primero, de 100 a 200 K para el segundo y así sucesivamente. Esto permite crear un modo de sincronización que combina las ventajas de la sincronización rápida (validación inmediata de los datos devueltos) con las de la sincronización warp (recuperación de fragmentos grandes de datos desde múltiples orígenes en simultáneo). El diagrama siguiente muestra un ejemplo de Unitrie que muestra los tamaños de subárboles de nodos. El trie puede dividirse en tres fragmentos que contengan casi la misma cantidad de datos cada uno, y a cada uno se lo solicitará para un par diferente. Aunque el solicitante no conozca el contenido y los límites de cada fragmento, sí conoce el tamaño de los fragmentos por anticipado. Cada fragmento puede verificarse de manera eficiente e independiente cuando se lo recibe. A algunos nodos internos se los incluye en más de un fragmento, para posibilitar la verificación.
Un Unitrie de estado dividido en tres fragmentos verificables independientemente
No obstante otro enorme beneficio de la Unitrie es que al almacenar el tamaño del nodo de trie, un nodo de red puede mostrar el porcentaje de finalización del estado de sincronización y estimar el tiempo restante para completar la sincronización.
Reducción del tamaño de la blockchain mediante desduplicación automática de código
Al combinar código y celdas de almacenamiento en una única base de datos direccionada por contenido, los nodos que contienen la misma clave/valor se almacenan una sola vez en la base de datos. Esto brinda desduplicación automática de datos, lo cual, en el caso de código de contratos, puede reducir el tamaño de la blockchain sin necesidad de contar con un mecanismo de desduplicación aparte o de usar técnicas de compresión de datos. Los nodos de código del trie siempre contendrán el mismo prefijo (0x80); por ende, si el código es el mismo, eso implica que el hash de nodo es el mismo y el almacenamiento es el mismo.
Ejecución más veloz de EXTCODESIZE
Cada nodo del Unitrie contiene un campo que crea un caché del tamaño de los datos almacenados en ese nodo. En el trie de Ethereum, consultar el tamaño de los datos del nodo obliga a capturar los datos de la base de datos. El Unitrie puede responder a consultas de tamaño, como las generadas por el código de operación EXTCODESIZE, por medio de consultas a este nuevo campo, y sin capturar el código del disco duro. El código de operación EXTCODESIZE se ha utilizado en el pasado para efectuar ataques de DoS a ciertas implementaciones de Ethereum; el Unitrie proporciona inmunidad a este tipo de ataques.
Detalles del método de actualización
Ninguna blockchain ha realizado jamás una actualización que cambiara la base de datos de estado cuando esta base de datos está asignada al encabezado de bloque. Por consiguiente, la actualización será la primera de su tipo. Básicamente, la actualización se produce en dos fases. La nueva versión de software calculará la nueva raíz del trie, pero continuará derivando la raíz anterior por medio de un algoritmo dinámico que convierte estructuralmente el nuevo trie de estado al trie anterior sobre la marcha, seguido de una bifurcación dura en la cual se asigna y verifica la nueva raíz de estado, y ya no se producen más conversiones dinámicas. En realidad, no solo debe convertirse el trie de estado, sino también los tries de transacción y recibo.
Deben ocurrir varias cosas para que pueda actualizarse la red con buenos resultados. Se lanzará una nueva versión del software de nodo completo en el tiempo R. La nueva versión contiene puntos de control periódicos desde el bloque génesis hasta un bloque en particular en el tiempo C. El tiempo C es anterior al tiempo R. Luego hay un intervalo en el cual se actualizarán los nodos antes de la bifurcación dura en el tiempo H. El siguiente diagrama representa la línea de tiempo:
La línea de tiempo de una actualización de red para el Unitrie
Cuando se instale la nueva actualización (que llamaremos 0.7.0), el nodo completo debe reestablecer su base de datos de estado de acuerdo con las nuevas reglas. Puede o bien migrar el estado actual o recalcular el estado mediante el reprocesamiento de todos los bloques desde el génesis hasta la mejor punta de cadena. Para la actualización de RSK, optamos por el reprocesamiento. Esto garantiza que las bases de datos de nodos completos queden sincronizadas a la perfección, aunque la base de datos anterior haya estado dañada antes de algún modo.
El evento C se escoge de manera tal que tenga lugar unas dos semanas antes que la bifurcación dura. Los usuarios deben actualizar su software de nodo completo después de la fecha de lanzamiento R, pero antes de la fecha de bifurcación dura H. Durante el período C-H, los nodos calcularán las raíces de estado de trie tanto nuevas como viejas. La raíz de estado anterior se calculará de forma dinámica a partir del nuevo trie de estado. Los nodos ligeros (también denominados nodos SPV) podrían decidir no validar las raíces de estado durante este breve intervalo, para reducir la carga de CPU. Esto se debe a que, de todas formas, los nodos ligeros siguen la tasa de hash. Además, los nodos pueden reducir la sobrecarga de validación durante este período; una manera sería verificar una de cada 10 asignaciones de raíces de estado durante el intervalo C-H. Sin embargo, el primer bloque después de la bifurcación dura ya no calculará ni validará raíces de estado viejas. Si la acepta la comunidad, prevemos que la bifurcación no traerá ningún inconveniente.
Resumen
El Unitrie, que RSK propuso en 2016, es una mejora notable para almacenamiento de estado en blockchains basadas en cuentas, tales como RSK, y ofrece un rendimiento mucho mayor de nodos completos. El Unitrie mejora la descentralización mediante la reducción de los recursos necesarios para nodos completos, mejora la capacidad de procesamiento de transacciones porque posibilita una mejor ejecución en paralelo, previene ataques de DoS al guardar en caché los tamaños de cargas y reducir los tamaños de cuentas, aumenta la equidad debido a que permite un mejor alquiler de almacenamiento, y reduce el tiempo de sincronización mediante compresión del estado.
Sabemos que actualizar una red para usar el Unitrie es un desafío, pero creemos que ha llegado el momento de ir tras este cambio. RSK Labs está terminando el código de referencia y agregando los toques finales a las RSKIP mientras la comunidad de RSK evalúa el cambio. En los próximos meses esperamos realizar una actualización segura de red para activar el Unitrie.