Un agradecimiento especial a Dankrad Feist y Aditya Asgaonkar por la revisión.
Sharding es el futuro de la escalabilidad de Ethereum, y será clave para ayudar al ecosistema a admitir miles de transacciones por segundo y permitir que grandes partes del mundo usen la plataforma regularmente a un costo asequible. Sin embargo, también es uno de los conceptos más incomprendidos en el ecosistema Ethereum y en los ecosistemas blockchain en general. Se refiere a un conjunto muy específico de ideas con propiedades muy específicas, pero a menudo se combina con técnicas que tienen propiedades de seguridad muy diferentes y, a menudo, mucho más débiles. El propósito de esta publicación será explicar exactamente qué propiedades específicas proporciona la fragmentación, en qué se diferencia de otras tecnologías que no fragmentan y qué sacrificios tiene que hacer un sistema fragmentado para lograr estas propiedades.
La mejor manera de describir la fragmentación comienza con la declaración del problema que dio forma e inspiró la solución: el trilema de escalabilidad .
El trilema de escalabilidad dice que hay tres propiedades que una cadena de bloques intenta tener, y que, si te apegas a técnicas "simples", solo puedes obtener dos de esas tres . Las tres propiedades son:
Escalabilidad : la cadena puede procesar más transacciones de las que un solo nodo regular (piense: una computadora portátil de consumo) puede verificar.
Descentralización : la cadena puede funcionar sin dependencias de confianza en un pequeño grupo de grandes actores centralizados. Por lo general, esto se interpreta en el sentido de que no debe haber ninguna confianza (o incluso una suposición de mayoría honesta) de un conjunto de nodos a los que no puede unirse con solo una computadora portátil de consumo.
Seguridad : la cadena puede resistir un gran porcentaje de nodos participantes que intentan atacarla (idealmente el 50%; cualquier valor superior al 25% está bien, el 5% definitivamente no está bien).
Ahora podemos ver las tres clases de "soluciones fáciles" que solo obtienen dos de las tres:
Cadenas de bloques tradicionales , incluidas Bitcoin, pre-PoS/sharding Ethereum, Litecoin y otras cadenas similares. Estos dependen de que cada participante ejecute un nodo completo que verifica cada transacción, por lo que tienen descentralización y seguridad, pero no escalabilidad.
Cadenas de alto TPS , incluida la familia DPoS, pero también muchas otras. Estos se basan en una pequeña cantidad de nodos (a menudo 10-100) que mantienen el consenso entre ellos, y los usuarios deben confiar en la mayoría de estos nodos. Esto es escalable y seguro (usando las definiciones anteriores), pero no está descentralizado.
Ecosistemas multicadena : esto se refiere al concepto general de "escalamiento horizontal" al tener diferentes aplicaciones en diferentes cadenas y usar protocolos de comunicación entre cadenas para hablar entre ellas. Esto es descentralizado y escalable, pero no es seguro, porque un atacante solo necesita obtener una mayoría de nodos de consenso en una de las muchas cadenas (a menudo <1% de todo el ecosistema) para romper esa cadena y posiblemente causar efectos dominó que causan gran daño a las aplicaciones en otras cadenas.
Sharding es una técnica que te da los tres. Una cadena de bloques fragmentada es:
El resto de la publicación describirá cómo las cadenas de bloques fragmentadas logran hacer esto.
La versión más fácil de entender de la fragmentación es la fragmentación mediante muestreo aleatorio. La fragmentación a través del muestreo aleatorio tiene propiedades de confianza más débiles que las formas de fragmentación que estamos construyendo en el ecosistema Ethereum, pero utiliza una tecnología más simple.
La idea central es la siguiente. Suponga que tiene una cadena de prueba de participación con un gran número (por ejemplo, 10000) de validadores, y tiene un gran número (por ejemplo, 100) de bloques que deben verificarse. Ninguna computadora es lo suficientemente potente como para validar todos estos bloques antes de que llegue el siguiente conjunto de bloques.
Por lo tanto, lo que hacemos es dividir aleatoriamente el trabajo de verificación . Mezclamos aleatoriamente la lista de validadores y asignamos los primeros 100 validadores de la lista mezclada para verificar el primer bloque, los segundos 100 validadores de la lista mezclada para verificar el segundo bloque, etc. Un grupo de validadores seleccionado al azar que se asigna a verificar un bloque (o realizar alguna otra tarea) se llama comité .
Cuando un validador verifica un bloque, publica una firma que certifica que lo hizo. Todos los demás, en lugar de verificar 100 bloques completos, ahora solo verifican 10000 firmas, una cantidad de trabajo mucho menor, especialmente con la agregación de firmas BLS . En lugar de que cada bloque se transmita a través de la misma red P2P, cada bloque se transmite en una subred diferente y los nodos solo necesitan unirse a las subredes correspondientes a los bloques de los que son responsables (o en los que están interesados por otras razones).
Considere lo que sucede si la potencia de cómputo de cada nodo aumenta en 2x. Debido a que cada nodo ahora puede validar de manera segura 2 veces más firmas, podría reducir el tamaño mínimo del depósito de participación para admitir 2 veces más validadores y, por lo tanto, puede crear 200 comités en lugar de 100.
Por lo tanto, puede verificar 200 bloques por ranura en lugar de 100. Además, cada bloque individual podría ser 2 veces más grande. Por lo tanto, tiene 2 veces más bloques de 2 veces el tamaño, o 4 veces más capacidad de cadena en total.
Podemos introducir algo de jerga matemática para hablar sobre lo que está pasando. Usando la notación Big O , usamos " O(C) " para referirnos a la capacidad computacional de un solo nodo. Una cadena de bloques tradicional puede procesar bloques de tamaño O(C) . Una cadena fragmentada como la descrita anteriormente puede procesar bloques O(C) en paralelo (recuerde, el costo de cada nodo para verificar cada bloque indirectamente es O(1) porque cada nodo solo necesita verificar un número fijo de firmas), y cada bloque tiene capacidad O(C) , por lo que la capacidad total de la cadena fragmentada es O(C2) . Es por eso que llamamos a este tipo de fragmentación fragmentación cuadrática , y este efecto es una razón clave por la que pensamos que, a largo plazo, la fragmentación es la mejor manera de escalar una cadena de bloques.
Hay dos diferencias clave:
Ambas diferencias aseguran que la fragmentación crea un entorno para aplicaciones que preserva las propiedades de seguridad clave de un entorno de cadena única, de una manera que los ecosistemas de cadenas múltiples fundamentalmente no lo hacen.
Un estribillo común en los círculos de Bitcoin, y con el que estoy completamente de acuerdo, es que las cadenas de bloques como Bitcoin (o Ethereum) NO se basan completamente en una suposición mayoritaria honesta . Si hay un ataque del 51% en dicha cadena de bloques, entonces el atacante puede hacer algunas cosas desagradables, como revertir o censurar transacciones, pero no puede insertar transacciones no válidas. E incluso si revierten o censuran las transacciones, los usuarios que ejecutan nodos normales podrían detectar fácilmente ese comportamiento, por lo que si la comunidad desea coordinarse para resolver el ataque con una bifurcación que le quita el poder al atacante, podrían hacerlo rápidamente.
La falta de esta seguridad adicional es una debilidad clave de las cadenas de alto TPS más centralizadas . Tales cadenas no tienen, y no pueden tener, una cultura de usuarios regulares que ejecutan nodos, por lo que los principales nodos y jugadores del ecosistema pueden unirse mucho más fácilmente e imponer un cambio de protocolo que a la comunidad le desagrada mucho. Peor aún, los nodos de los usuarios lo aceptarían por defecto. Después de algún tiempo, los usuarios se darían cuenta, pero para entonces el cambio de protocolo forzado sería un hecho consumado: la responsabilidad de la coordinación recaería sobre los usuarios para rechazar el cambio, y tendrían que tomar la dolorosa decisión de revertir el valor de un día o más de actividad que todos habían pensado que ya estaba finalizada.
Idealmente, queremos tener una forma de fragmentación que evite el 51% de las suposiciones de confianza para la validez y conserve el poderoso baluarte de seguridad que obtienen las cadenas de bloques tradicionales de la verificación completa. Y esto es exactamente de lo que se ha tratado gran parte de nuestra investigación en los últimos años.
Podemos dividir el problema de validación escalable a prueba de ataques del 51 % en dos casos:
Validación de cómputo : verificar que algún cómputo se haya realizado correctamente, asumiendo que tiene posesión de todas las entradas para el cómputo.
Validar la disponibilidad de los datos : verificar que las entradas para el cálculo en sí estén almacenadas de alguna forma donde pueda descargarlas si realmente lo necesita; esta verificación debe realizarse sin descargar las entradas completas (porque los datos podrían ser demasiado grandes para descargar para cada bloque).
La validación de un bloque en una cadena de bloques implica tanto el cálculo como la verificación de la disponibilidad de datos: debe estar convencido de que las transacciones en el bloque son válidas y que el nuevo hash raíz del estado reclamado en el bloque es el resultado correcto de ejecutar esas transacciones, pero también debe estar convencido de que se publicaron suficientes datos del bloque para que los usuarios que descargan esos datos puedan calcular el estado y continuar procesando la cadena de bloques. Esta segunda parte es un concepto muy sutil pero importante llamado problema de disponibilidad de datos ; más sobre esto más adelante.
El cómputo de validación escalable es relativamente fácil; existen dos familias de técnicas: pruebas de fraude y ZK-SNARKs .
Las dos tecnologías se pueden describir simplemente de la siguiente manera:
C
con la entrada X
, obtienes la salida Y
". Usted confía en estos mensajes de forma predeterminada, pero deja abierta la oportunidad de que otra persona con un depósito apostado haga un desafío (un mensaje firmado que dice "No estoy de acuerdo, la salida es Z"). Solo cuando hay un desafío, todos los nodos ejecutan el cálculo. Cualquiera de las dos partes que se equivocó pierde su depósito, y todos los cálculos que dependen del resultado de ese cálculo se vuelven a calcular.C
en la entrada X
da como resultado la salida Y
". La prueba es criptográficamente "sólida": si C(x)
no es igual a Y
, es computacionalmente inviable hacer una prueba válida. La prueba también es rápida de verificar, incluso si la ejecución de C
lleva una gran cantidad de tiempo. Consulte esta publicación para obtener más detalles matemáticos sobre ZK-SNARK.
El cómputo basado en pruebas de fraude es escalable porque "en el caso normal" reemplaza la ejecución de un cómputo complejo con la verificación de una sola firma. Existe el caso excepcional, en el que tiene que verificar el cálculo en la cadena porque hay un desafío, pero el caso excepcional es muy raro porque activarlo es muy costoso (el reclamante original o el retador pierde un gran depósito). Los ZK-SNARK son conceptualmente más simples: simplemente reemplazan un cálculo con una verificación de prueba mucho más barata, pero la matemática detrás de su funcionamiento es considerablemente más compleja.
Existe una clase de sistema semiescalable que solo verifica el cálculo de manera escalable, al mismo tiempo que requiere que cada nodo verifique todos los datos. Esto se puede hacer bastante efectivo mediante el uso de un conjunto de trucos de compresión para reemplazar la mayoría de los datos con computación. Este es el reino de los rollups .
No se puede utilizar una prueba de fraude para verificar la disponibilidad de los datos. Las pruebas de fraude para el cómputo se basan en el hecho de que las entradas del cómputo se publican en la cadena en el momento en que se envía el reclamo original y, por lo tanto, si alguien cuestiona, la ejecución del desafío se lleva a cabo exactamente en el mismo "entorno" en el que se realizó la ejecución original. sucediendo. En el caso de comprobar la disponibilidad de los datos, no puedes hacerlo, porque el problema es precisamente que hay demasiados datos que comprobar para publicarlos en cadena. Por lo tanto, un esquema a prueba de fraude para la disponibilidad de datos se topa con un problema clave: alguien podría afirmar que "los datos X están disponibles" sin publicarlos, esperar a ser cuestionados y solo entonces publicar los datos X y hacer que el cuestionador aparezca ante el resto de la gente. red sea incorrecta.
Esto se amplía en el dilema del pescador :
La idea central es que los dos "mundos", uno donde V1 es un editor malvado y V2 es un retador honesto y el otro donde V1 es un editor honesto y V2 es un retador malvado, son indistinguibles para cualquiera que no esté tratando de descargar ese dato en particular en ese momento. Y, por supuesto, en una cadena de bloques descentralizada escalable, cada nodo individual solo puede esperar descargar una pequeña parte de los datos, por lo que solo una pequeña parte de los nodos vería algo sobre lo que sucedió, excepto por el mero hecho de que hubo un desacuerdo.
El hecho de que sea imposible distinguir quién tenía razón y quién estaba equivocado hace que sea imposible tener un esquema funcional a prueba de fraudes para la disponibilidad de datos.
Desafortunadamente, la mera validez no es suficiente para garantizar que la cadena de bloques funcione correctamente. Esto se debe a que si la cadena de bloques es válida pero no todos los datos están disponibles , los usuarios no tienen forma de actualizar los datos que necesitan para generar pruebas de que cualquier bloque futuro es válido. Un atacante que genera un bloque válido pero no disponible pero luego desaparece puede detener la cadena de manera efectiva. Alguien también podría retener los datos de la cuenta de un usuario específico hasta que el usuario pague un rescate, por lo que el problema no es simplemente un problema de vida.
Hay algunos argumentos sólidos de teoría de la información de que este problema es fundamental, y no hay ningún truco inteligente (por ejemplo, que involucre acumuladores criptográficos ) que pueda solucionarlo. Consulte este documento para obtener más información.
La clave es una tecnología llamada muestreo de disponibilidad de datos . El muestreo de disponibilidad de datos funciona de la siguiente manera:
Los códigos de borrado transforman un problema de "verificación del 100 % de disponibilidad" (todos los datos están disponibles) en un problema de "verificación del 50 % de disponibilidad" (al menos la mitad de las piezas están disponibles). El muestreo aleatorio resuelve el problema de disponibilidad del 50%. Si hay menos del 50 % de los datos disponibles, es casi seguro que al menos una de las comprobaciones fallará, y si al menos el 50 % de los datos están disponibles, mientras que algunos nodos pueden no reconocer un bloque como disponible, se necesita solo un nodo honesto para ejecutar el procedimiento de reconstrucción del código de borrado para recuperar el 50% restante del bloque. Y así, en lugar de necesitar descargar 1 MB para verificar la disponibilidad de un bloque de 1 MB, solo necesita descargar unos pocos kilobytes. Esto hace que sea factible ejecutar la verificación de disponibilidad de datos en cada bloque. Consulte esta publicación para ver cómo se puede implementar esta verificación de manera eficiente con subredes punto a punto.
Se puede usar un ZK-SNARK para verificar que la codificación de borrado en una parte de los datos se realizó correctamente , y luego se pueden usar las ramas de Merkle para verificar fragmentos individuales. Alternativamente, puede usar compromisos polinómicos (por ejemplo, compromisos de Kate (también conocido como KZG) , que esencialmente borran la codificación y prueban elementos individuales y verificación de corrección, todo en un componente simple, y eso es lo que está usando la fragmentación de Ethereum.
Suponga que tiene 100 bloques y desea verificar de manera eficiente la corrección de todos ellos sin depender de los comités. Necesitamos hacer lo siguiente:
Cada cliente realiza un muestreo de disponibilidad de datos en cada bloque, verificando que los datos en cada bloque estén disponibles, mientras descarga solo unos pocos kilobytes por bloque, incluso si el bloque en su totalidad es de un megabyte o más grande. Un cliente solo acepta un bloque cuando todos los datos de sus desafíos de disponibilidad han sido respondidos correctamente.
Ahora que hemos verificado la disponibilidad de los datos, es más fácil verificar la corrección. Hay dos técnicas:
En cualquiera de los casos anteriores, cada cliente solo necesita hacer una pequeña cantidad de trabajo de verificación por bloque, sin importar cuán grande sea el bloque. En el caso de las pruebas de fraude, ocasionalmente los bloques deberán verificarse por completo en la cadena, pero esto debería ser extremadamente raro porque desencadenar incluso un desafío es muy costoso.
¡Y eso es todo! En el caso de la fragmentación de Ethereum, el plan a corto plazo es hacer bloques fragmentados solo de datos ; es decir, los fragmentos son puramente un "motor de disponibilidad de datos", y es el trabajo de los paquetes acumulativos de capa 2 utilizar ese espacio de datos seguro, además de pruebas de fraude o ZK-SNARK, para implementar capacidades de procesamiento de transacciones seguras de alto rendimiento. Sin embargo, es completamente posible crear un sistema integrado de este tipo para agregar una ejecución de alto rendimiento "nativa".
El objetivo clave de la fragmentación es acercarse lo más posible a la replicación de las propiedades de seguridad más importantes de las cadenas de bloques tradicionales (no fragmentadas), pero sin la necesidad de que cada nodo verifique personalmente cada transacción.
La fragmentación se acerca bastante. En una cadena de bloques tradicional:
En una cadena de bloques fragmentada con funciones de seguridad avanzadas:
Los bloques no válidos no pueden pasar porque:
Los bloques no disponibles no pueden pasar porque:
Las cadenas tradicionales de alto TPS sin fragmentación no tienen forma de proporcionar estas garantías. Los ecosistemas multicadena no tienen forma de evitar el problema de que un atacante seleccione una cadena para el ataque y la controle fácilmente (las cadenas podrían compartir la seguridad, pero si esto se hiciera mal, se convertiría en una cadena tradicional de alto TPS de facto). con todas sus desventajas, y si se hiciera bien, solo sería una implementación más complicada de las técnicas de fragmentación anteriores).
Las cadenas laterales dependen en gran medida de la implementación, pero suelen ser vulnerables a las debilidades de las cadenas tradicionales de alto TPS (esto es si comparten mineros/validadores) o a las debilidades de los ecosistemas multicadena (esto es si no comparten mineros/validadores). ). Las cadenas fragmentadas evitan estos problemas.
Sin embargo, hay algunas grietas en la armadura del sistema fragmentado . Notablemente:
Estas son preocupaciones válidas, aunque, en nuestra opinión, son superadas con creces por la reducción en la centralización a nivel de usuario habilitada al permitir que más aplicaciones se ejecuten en cadena en lugar de a través de servicios centralizados de capa 2. Dicho esto, estas preocupaciones, especialmente las dos últimas, son en la práctica la restricción real para aumentar el rendimiento de una cadena fragmentada más allá de cierto punto. Hay un límite para la cuadrática de la fragmentación cuadrática.
Por cierto, los crecientes riesgos de seguridad de las cadenas de bloques fragmentadas si su rendimiento se vuelve demasiado alto también son la razón clave por la que se ha abandonado en gran medida el esfuerzo por extenderse a la fragmentación supercuadrática ; parece que mantener la fragmentación cuadrática solo cuadrática es realmente el medio feliz.
Una alternativa a la fragmentación que se propone a menudo es tener una cadena que esté estructurada como una cadena centralizada de alto TPS, excepto que utiliza muestras de disponibilidad de datos y fragmentación en la parte superior para permitir la verificación de validez y disponibilidad.
Esto mejora las cadenas centralizadas de alto TPS que existen hoy en día, pero sigue siendo considerablemente más débil que un sistema fragmentado. Esto se debe a algunas razones:
Los sistemas fragmentados correctamente son mejores como capa base. Dada una capa base fragmentada, siempre puede crear un sistema de producción centralizado (por ejemplo, porque desea un dominio de alto rendimiento con capacidad de composición síncrona para defi ) superpuesta en capas al construirlo como un paquete acumulativo. Pero si tiene una capa base que depende de la producción de bloques centralizada, no puede construir una capa 2 más descentralizada encima.
También publicado aquí .