Fragmento de blockchain

Hola a todos, soy uno de los desarrolladores de Near Protocol, que, entre otras cosas, implementa el fragmentación, y en este artículo quiero decir en detalle qué fragmentación hay en la cadena de bloques, cómo funciona y abordar una serie de problemas que surgen al intentar construirlo.


Es bien sabido que Ethereum, la plataforma dApps más popular, procesa menos de 20 transacciones por segundo. Debido a esta restricción, el precio de las transacciones y el tiempo para confirmarlas son muy altos: a pesar del hecho de que un bloque se publica en Ethereum una vez cada 10-12 segundos, según ETH Gas Station, el tiempo entre el envío de una transacción y cómo realmente cae en el bloque es un promedio de 1.2 minutos El ancho de banda bajo, los precios altos y la confirmación de transacciones largas no permiten lanzar servicios de alto rendimiento en Ethereum.


La razón principal por la que Ethereum no puede procesar más de 20 transacciones por segundo es porque cada nodo en Ethereum tiene que verificar cada transacción. Durante los cinco años transcurridos desde el lanzamiento de Ethereum, se han propuesto muchas ideas para resolver este problema. Estas soluciones se pueden dividir en dos grupos: aquellos que ofrecen delegar transacciones a un pequeño grupo de nodos con muy buen hardware, y aquellos que ofrecen a cada nodo procesar solo un subconjunto de todas las transacciones. Un ejemplo del primer enfoque es Thunder , en el que los bloques son creados por un solo nodo, lo que permite, según los desarrolladores, recibir 1200 transacciones por segundo, que es 100 veces más que Ethereum. Otros ejemplos de la primera categoría son Algorand , SpaceMesh , Solana . Todos estos protocolos mejoran varios aspectos del protocolo y le permiten realizar más transacciones que en Ethereum, pero todos están limitados por la velocidad de una máquina (aunque muy poderosa).


El segundo enfoque, en el que cada nodo procesa solo un subconjunto de transacciones, se llama Sharding. Así es como la Fundación Ethereum planea aumentar el ancho de banda de Ethereum.


En esta publicación, te contaré cómo funciona Sharding en Blockchain usando el ejemplo de varios protocolos que se encuentran actualmente en desarrollo.


Terminología

Como la terminología no está estandarizada, utilizaré los siguientes términos rusos en el artículo:


Un blockchain es una tecnología en general o una estructura de datos que contiene todos los bloques, incluidos los tenedores.


Una cadena es una cadena particular en la cadena de bloques, es decir, todos los bloques a los que se puede acceder a partir de un bloque que usa enlaces al bloque anterior.


La cadena canónica es una cadena en la cadena de bloques que el participante que observa la cadena de bloques considera la cadena actual. Por ejemplo, en la cadena de bloques de Prueba de trabajo, será la cadena con la mayor complejidad.


Una red es una gran cantidad de participantes que construyen y usan blockchain.


Un nodo es un servidor que admite o utiliza una red.


El fragmentado más fácil


En la implementación más simple, en lugar de admitir una cadena de bloques, admitiremos varias y llamaremos a cada una de estas cadenas de bloques un "fragmento". Cada fragmento es compatible con un conjunto independiente de nodos que verifican las transacciones y crean bloques. En lo sucesivo, llamaré a tales validadores de nodos.


Cada fragmento es responsable de un subconjunto de contratos y cuentas. Suponga por ahora que las transacciones siempre operan solo con contratos y cuentas dentro del mismo fragmento. Un diseño tan simplificado es suficiente para mostrar algunos problemas interesantes y características de fragmentación.


Nombramiento de validadores y Blockchain central


El primer problema con el hecho de que cada fragmento tiene sus propios validadores es que si tenemos 10 shadras, entonces cada fragmento es ahora 10 veces menos confiable de lo que sería una cadena de bloques. Entonces, si una cadena de bloques con validadores X decide hacer una bifurcación dura en un sistema de fragmentos con 10 fragmentos, y rompe los validadores X entre 10 fragmentos, solo hay validadores X / 10 en cada fragmento, y obtener el control sobre el fragmento requiere obtener un control superior al 5.1% (51 % / 10) validadores.


Lo que lleva a la primera pregunta interesante: ¿quién asigna validadores a los fragmentos? Tener control sobre el 5.1% de los validadores es un problema solo si todos los 5.1% de los validadores están en el mismo fragmento. Si los validadores mismos no pueden elegir a qué fragmento están asignados, obtener el control sobre el 5,1% de los validadores antes de asignarlos a los fragmentos no les permitirá obtener el control sobre ningún fragmento.


imagen


Casi todos los diseños de fragmentos propuestos existentes utilizan alguna fuente de números aleatorios para asignar validadores a los fragmentos. Obtener números aleatorios en un sistema distribuido en el que los participantes no confían entre sí es un problema que hoy no se resuelve por completo, que no abordaremos en este artículo, y simplemente asumimos que tenemos una fuente de números aleatorios.


Tanto la recepción de números aleatorios como la designación de validadores son cálculos a escala de todo el sistema que no son específicos de ningún fragmento en particular. Para tales cálculos, los diseños modernos de blockchain de fragmentos tienen una blockchain dedicada adicional que existe únicamente para realizar cálculos en todo el sistema. Además de los números aleatorios y la designación de validadores, dichos cálculos pueden incluir obtener hashes de los últimos bloques de fragmentos y almacenarlos; procesar colaterales en sistemas de Prueba de Estaca, y estudiar evidencia de comportamiento inapropiado con la selección asociada de tales colaterales; reequilibrar fragmentos, si se proporciona dicha función. Tal cadena de bloques se llama la cadena Beacon en Ethereum 2.0 y Near Protocol, la cadena Relay en PolkaDot y el Cosmos Hub en Cosmos.


En esta publicación llamaremos a dicha cadena de bloques la "cadena de bloques central". La existencia de una cadena de bloques central nos lleva al siguiente tema interesante: fragmentación cuadrática.


Fragmentación cuadrática


El fragmentación a menudo se presenta como una solución que se escala infinitamente con el número creciente de nodos. Probablemente, realmente puede crear un sistema con esta propiedad, pero los sistemas con una cadena de bloques central tienen un límite superior en la cantidad de fragmentos y, como resultado, no tienen una escalabilidad infinita. Es fácil entender por qué: la cadena de bloques central realiza algunos cálculos, como asignar validadores y preservar los últimos estados de fragmentos, cuya complejidad es proporcional al número de fragmentos. Dado que la cadena de bloques central en sí no está fragmentada, y su rendimiento está limitado por el rendimiento de cada nodo, el número de fragmentos que puede soportar es limitado.


Veamos cómo cambia el rendimiento de todo el sistema si la potencia de los nodos que lo soportan aumenta k veces. Cada fragmento podrá procesar k veces más transacciones, y la cadena de bloques central podrá admitir k veces más fragmentos. Por lo tanto, el rendimiento de todo el sistema crecerá k ^ 2 veces. De ahí el nombre de "fragmentación cuadrática".


Es difícil predecir cuánto fragmento puede soportar la cadena de bloques central hoy en día, pero lo más probable es que en el futuro cercano no nos acerquemos al límite de transacción para una cadena de bloques fragmentada con fragmentación cuadrática. Lo más probable es que pronto nos encontremos con el límite de cuántos nodos se necesitan para admitir tal cantidad de fragmentos.


Fragmentación del estado


El estado es toda la información sobre todas las cuentas y contratos. Hasta ahora, hemos hablado de fragmentación en general, sin especificar qué es exactamente fragmentación. Los nodos en la cadena de bloques realizan las siguientes tres tareas: 1) realizar transacciones 2) reenviar transacciones y bloques a otros nodos y 3) almacenar el estado y la historia de la cadena de bloques. Cada una de estas tres tareas está asociada con una carga cada vez mayor en los nodos:


  1. La necesidad de realizar transacciones requiere más potencia informática con un aumento en el número de transacciones;
  2. La necesidad de reenviar transacciones requiere más ancho de banda de red a medida que crecen las transacciones;
  3. La necesidad de mantener el estado y el historial requiere más espacio en disco a medida que aumenta el tamaño del estado y / o el historial. Es importante tener en cuenta que, a diferencia de los dos primeros puntos, la cantidad de espacio en disco requerido aumenta incluso si el número de transacciones por unidad de tiempo no cambia.

De la lista anterior, puede parecer que el espacio en disco es el mayor problema, ya que solo el espacio en disco aumenta incluso si el número de transacciones no aumenta, pero en la práctica no lo es. Hoy, el estado de Ethereum toma aproximadamente 100 GB, que se pueden guardar fácilmente en cualquier máquina moderna, pero la cantidad de transacciones que Ethereum puede procesar se limita a varias decenas por segundo, dependiendo de la potencia informática y la red.


Zilliqa es el proyecto más famoso que fragmenta la informática y la red pero no el estado. Calcular el fragmentación es más simple que el estado de fragmentación, porque todos los nodos tienen todos los estados, y aún pueden ejecutar fácilmente contratos que causan otros contratos o afectan cuentas en diferentes fragmentos. En estos aspectos, el diseño de Zilliqa es demasiado simplificado, las críticas al diseño en inglés se pueden leer aquí .


Si bien se propuso la fragmentación de estado sin fragmentación de cálculo, no conozco ningún proyecto que realmente haga esto, por lo que asumiremos que la fragmentación de estado implica la fragmentación de los cálculos.


En la práctica, el hecho de que el estado esté fragmentado de alguna manera aísla los fragmentos, lo que les permite ser cadenas de bloques independientes, como definimos anteriormente. Los validadores en fragmentos solo almacenan un estado específico de su fragmento, y solo las transacciones que afectan a este estado se ejecutan y reenvían. Esto reduce la carga en el procesador, el disco y la red linealmente con el número de fragmentos, pero trae nuevos problemas, como las transacciones entre fragmentos.


Transacciones entre fragmentos


Hasta ahora, hemos visto fragmentos como cadenas de bloques independientes en términos de cómo ejecutan transacciones. Con este diseño, por ejemplo, es imposible completar una transacción que transfiere dinero entre dos cuentas en dos fragmentos diferentes, o causar contacto en un fragmento de un contrato en otro. Me gustaría apoyar ambos escenarios.


Por simplicidad, solo consideraremos las transacciones que transfieren dinero, y asumiremos que cada participante tiene una cuenta en exactamente un fragmento. Si un participante en un fragmento desea transferir dinero a un participante en el mismo fragmento, los validadores de este fragmento pueden procesar esta transacción y aplicarla al estado. Pero si, por ejemplo, Alice tiene una cuenta en el fragmento n. ° 1 y quiere enviar dinero a Bob con una cuenta en el fragmento n. ° 2, ni los validadores del fragmento n. ° 1 (que no pueden agregar dinero a Bob) ni los validadores del fragmento n. ° 2 (que no pueden obtener el dinero de Alice ) no puede completar la transacción y actualizar el estado.


Hay dos grandes grupos de enfoques para resolver este problema:


  1. Sincrónico : para cualquier transacción que involucre varios fragmentos, los bloques en fragmentos que contienen actualizaciones de estado para esta transacción se producen simultáneamente, y los validadores en estos fragmentos trabajan juntos para crear tales bloques. El diseño más elaborado de este enfoque, conocido por mí, es Merge Blocks, descrito (en inglés) aquí .


  2. Asíncrono : una transacción entre fragmentos se ejecuta en fragmentos que afecta, de forma asíncrona: la parte de la transacción que agrega dinero a Bob se ejecuta en el fragmento # 2 cuando los validadores en el fragmento tienen alguna evidencia de que la parte de la transacción que resta dinero de Alice se ejecutó en fragmento # 1. Este enfoque es más popular en los sistemas que se desarrollan actualmente debido al hecho de que no requiere sincronización adicional entre fragmentos para la producción de bloques. Tales sistemas se ofrecen hoy en Cosmos, Ethereum Serenity, Near Protocol, Kadena y otros. El problema con este enfoque es que si los bloques se producen de forma independiente, es probable que uno de los bloques que contiene la actualización de estado para la transacción no esté en la cadena canónica en su fragmento y, por lo tanto, la transacción solo se completará parcialmente. Por ejemplo, considere la figura a continuación. Muestra dos fragmentos en los que se produjeron los tenedores y una transacción entre fragmentos, cuya actualización de estado se refleja en los bloques A y X ', respectivamente. Si las cadenas AB y V'-X'-Y'-Z 'resultan ser canónicas en sus fragmentos, entonces la transacción está completamente finalizada. Si las cadenas A'-B'-C'-D 'y VX son canónicas, entonces la transacción se cancela por completo, lo cual es aceptable. Pero si, por ejemplo, AB y VX se vuelven canónicos, una parte de la transacción se finaliza, la otra se cancela y la transacción se completa parcialmente.



imagen


El escenario descrito anteriormente es uno de los grandes problemas de fragmentación, en el que todas las soluciones propuestas no son óptimas. Lo tocaremos un poco más abajo.


Mal comportamiento


Ahora que hemos descubierto cómo funcionan las cadenas de bloques de fragmentos y estudiamos los conceptos de cadena de bloques central, la designación de validadores y las transacciones de fragmentos cruzados, al final de este artículo veremos otro tema interesante: ¿qué puede hacer un participante que intenta atacar el sistema si logra obtener control sobre un número suficientemente grande de validadores en un fragmento.


Horquillas dirigidas


Si el participante tiene suficiente control sobre el fragmento, puede crear tenedores a propósito. Para crear tenedores, no importa qué consenso se use en los fragmentos, en particular, no importa si es BFT o no, si un número suficiente de validadores están bajo el control de un atacante, puede crear un tenedor. Por ejemplo, el objetivo de la bifurcación podría ser deshacer una transacción que pagó por algo fuera de la cadena de bloques.


Se afirma que obtener el control del 50% del fragmento es más fácil que el 50% de toda la red (por ejemplo, porque un participante puede intentar piratear o sobornar validadores después de haber sido asignado al fragmento). Por definición, las transacciones entre fragmentos cambian de estado en varios fragmentos. Tales cambios caerán en algunos bloques en las cadenas de bloques de los fragmentos correspondientes. Es necesario que todos estos bloques estén finalizados (es decir, pertenezcan a la cadena canónica en sus fragmentos respectivos) o que no todos estén finalizados (es decir, no pertenezcan a la cadena canónica en sus fragmentos). Dado que asumimos que algunos participantes con malas intenciones pueden, en principio, obtener el control sobre el fragmento, no podemos suponer que los tenedores no ocurrirán incluso si se alcanza el consenso bizantino, o si se construyó un gran número de bloques en la parte superior del bloque con la transacción.


Este problema tiene muchas soluciones, la más simple de las cuales es a veces guardar el hash del último bloque en el fragmento en la cadena de bloques central. El algoritmo de selección de cadena canónica en fragmentos luego se cambia para que ningún objetivo que contenga el último bloque almacenado en la cadena de bloques central canónico. Luego, para evitar por completo situaciones en las que la transacción se completó parcialmente debido al hecho de que algunos de los bloques que contienen su actualización de estado quedaron fuera de las cadenas canónicas, puede cambiar el algoritmo para ejecutar transacciones entre fragmentos de modo que el fragmento A no acepte la prueba de la transacción en el fragmento B hasta el bloque que contiene la actualización de estado para la transacción en el fragmento B no se guardó en la cadena de bloques central.


Crear bloques inválidos


Si el participante pudo obtener el control sobre un número suficientemente grande de validadores en el fragmento, puede intentar crear un bloque completamente inválido. Por ejemplo, suponga que antes del bloque, el estado era tal que Alice tenía 10 tokens, y en Bob - 0, el bloque contiene solo una transacción, que envía 10 tokens de la cuenta de Alice a la cuenta de Bob, pero en el nuevo estado refleja 0 tokens de Alice, y 1000 con Bob


imagen


En una cadena de bloques clásica, sin fragmentos, es imposible crear dicho bloque, porque todos los participantes, como aquellos que crean bloques y aquellos que simplemente usan la cadena de bloques, verifican todos los bloques e inmediatamente descartan cualquier bloque que contenga tales errores. Incluso si los validadores controlados por el atacante pueden construir la cadena más rápido, esto no les permitirá pasar la cadena más larga que contiene el bloque no válido como el canónico, porque todos los participantes de la red descartarán inmediatamente el bloque no válido y cualquier bloque que se haya construido encima. Los validadores honestos continuarán construyendo sobre el último bloque válido, y todos los participantes de la red verán su cadena como canónica.


imagen


La figura anterior muestra cinco validadores, tres de los cuales están bajo el control del atacante. Crearon el bloque no válido A ', y luego continuaron construyendo la cadena en la parte superior. Dos validadores privados descartaron inmediatamente el bloque A 'como no válido y continuaron construyendo sobre el último bloque válido que conocían, creando así una bifurcación. Como hay menos validadores en una cadena honesta que en una deshonesta, su cadena es más corta. Sin embargo, en la clásica cadena de bloques sin sombrear, todos los participantes en el sistema validan todos los bloques que ven. Por lo tanto, cualquier participante que use la cadena de bloques verá que A 'no es válido, lo descartará y, por lo tanto, descartará B', C 'y D' como está construido sobre el bloque no válido, y así todos los participantes verán AB como una cadena canónica.


En un diseño de fragmento, ningún participante puede validar todos los bloques en todas las cadenas de bloques. Por lo tanto, necesitamos algún tipo de mecanismo que permita a los validadores en un fragmento particular asegurarse de que en ningún momento en el pasado se haya creado un bloque no válido en otro fragmento del que recibieron una transacción entre fragmentos.


, , . , , ( ).


, :


  1. - . , 2/3 . , , , . , , , - , . , .
  2. - , , , , , . , zk-SNARKs ( zk, zero-knowledge, , non-zk SNARKs). , zk-SNARKs , .

, , , , . — .


Escribo mucho sobre blockchain y sharding en inglés. También entrevistamos periódicamente a autores de otros protocolos como Cosmos y Solana, profundizando en detalles técnicos. Si está interesado en el tema, puede seguir nuevas publicaciones y videos suscribiéndose a mi Twitter @AlexSkidanov .

Source: https://habr.com/ru/post/437924/


All Articles