Esta publicación es la segunda de una serie que explica un error que encontré en el cliente go-ethereum (Geth). Si aún no lo entiende, lea el primer artículo (traducción al chino). El error del que trata este artículo está en el descargador de estado del cliente Geth, y se puede usar para engañar al descargador para que no se sincronice correctamente con la red principal. Los atacantes pueden usar este error para establecer trampas para la cadena de bloques de Ethereum y activar arbitrariamente bifurcaciones duras. Cuando desea ejecutar un nodo Ethereum, primero debe sincronizar toda la red, es decir, descargar y calcular todos los datos necesarios para construir el estado de la cadena de bloques en el momento del último bloque. Según las propias necesidades del usuario, el método de sincronización puede ser una compensación entre seguridad y velocidad, por lo que (al momento de escribir este artículo) Geth admite dos modos de sincronización: sincronización completa y sincronización rápida. Como su nombre lo indica, la sincronización completa consiste en ejecutar de forma independiente todo el proceso de sincronización de la cadena de bloques de Ethereum. Esto significa que su nodo Geth descargará y verificará la Prueba de trabajo (PoW) de cada bloque, y además, calculará cada transacción en el bloque, por lo que el nodo puede generar la cadena de bloques localmente El último estado del nodo sin confiar en otros nodos. Este modo es más seguro, pero hay un gran sacrificio en la velocidad. Geth puede tardar días o semanas en sincronizarse por completo. Sin embargo, es posible que algunos usuarios no quieran esperar semanas. Tal vez estén presionados por el tiempo, o tal vez no sientan que el sacrificio valga la pena. Por lo tanto, Geth proporciona un modo: todos los datos de la cadena antes de un bloque reciente (llamado "bloque pivote") se sincronizan con un método más rápido, y solo se sincroniza la cadena de bloques después del bloque pivote. Use el algoritmo totalmente síncrono más lento. En el modo de sincronización rápida, Geth descargará bloques, pero solo seleccionará aleatoriamente algunos bloques para verificar la prueba de trabajo, en lugar de verificar cada bloque; además, ya no ejecutará transacciones por sí mismo, sino desde la red. El árbol de estado se descarga directamente de otros nodos de la red para obtener el estado final de la cadena de bloques. Por supuesto, Geth no confiará ciegamente en los datos del árbol de estado enviados por otros nodos, porque un nodo malicioso también puede afirmar que una cuenta tiene poco dinero (pero en realidad tiene mucho). Para comprender cómo Geth puede saber si los datos que recibe son correctos o no, primero debemos comprender el trie de Merkle-Patricia. Un árbol Merkle Patricia (MPT) es una estructura de datos clave en el cliente Geth, que es una combinación del árbol Merkle y el árbol Patricia. En pocas palabras, Patricia Tree almacena datos en una estructura de árbol basada en el prefijo de los datos. En comparación con otras tecnologías (como la tabla hash, el mapa hash), Patricia Tree en sí es muy adecuado para almacenar datos similares, aunque puede haber un sacrificio en la velocidad. Echemos un vistazo a cómo se almacenan varias palabras que comienzan con r en un árbol de Patricia. A continuación, hablemos del árbol de Merkle. En un árbol de Merkle, cada nodo de hoja es el valor hash de los datos y cada nodo que no es hoja es el valor hash de sus dos nodos secundarios. Si el usuario conoce la raíz de Merkle del árbol de Merkle (es decir, el valor hash superior) y quiere confirmar si ciertos datos están almacenados en el árbol, solo necesita usar una ruta en el árbol, el número de nodos involucrado en este camino es solo proporcional al logaritmo del número de nodos de hoja (no el número de nodos de hoja). Como se muestra en la figura a continuación, suponga que el usuario quiere probar que L2 está almacenado en este árbol, solo necesita proporcionar Hash 0-0 y Hash 1. A continuación, el verificador genera Hash 0-1, Hash 0 y Top Hash, y luego compara Top Hash con su raíz de Merkle esperada. EOS cayó por debajo de la marca de $3,2 con una caída intradiaria del 9,47 %: los datos de Huobi Global muestran que EOS cayó a corto plazo y cayó por debajo de la marca de $3,2, y ahora está en $3,1982, con una caída intradiaria del 9,47 %. , por favor haga un buen trabajo en el control de riesgos . [2021/1/11 15:49:28] El árbol Merkle Patricia combina la estructura de almacenamiento basada en prefijos del árbol Patricia con el árbol Merkle para crear una nueva estructura de datos, no solo es compatible con la autenticación criptográfica y mantiene un buen rendimiento de tiempo de ejecución. En un árbol de Merkle Patricia, las claves y los valores son cadenas de bytes arbitrarias. Para obtener el valor de una clave, primero convertimos la clave en una secuencia de caracteres hexadecimales, es decir, convertimos cada byte en dos caracteres hexadecimales. Luego, primero debemos consultar el nodo raíz para el siguiente nodo en función del primer carácter de la secuencia; después de obtener este nodo secundario, luego consultamos el nodo hacia abajo de acuerdo con el segundo carácter, y así sucesivamente hasta que encontremos el último nodo Obtener el último carácter. En el siguiente ejemplo, podemos ver que el árbol de Merkle Patricia en realidad contiene tres nodos diferentes. Los nodos extendidos (también conocidos como nodos cortos en el código base de Geth) están optimizados para almacenar una secuencia de caracteres. En el caso que se muestra en la figura a continuación, el nodo raíz almacena todas las claves que comienzan con a7, por lo que no es necesario usar dos nodos diferentes para representar a y 7. Un nodo de rama (o "nodo completo") contiene punteros a todos los caracteres posibles más una ranura adicional para almacenar el valor del nodo actual. Finalmente, el campo final de clave de un nodo hoja (también conocido como nodo de valor) debe coincidir con el sufijo 1 de la clave que almacena. Ahora que sabemos cómo funciona un árbol de Merkle Patricia, podemos comenzar a explorar qué es un árbol de estado global. La gran mayoría de los datos de blockchain se almacenan en un árbol de estado global. Si bien puede parecer conveniente concebir el árbol de estado como una entidad única dentro de cada bloque, en la práctica es extremadamente ineficiente replicar el árbol de estado completo para cada bloque porque el estado entre cada árbol de bloque solo tiene matices. Geth adopta un enfoque diferente. Como puede imaginar, Geth mantiene un grupo de nodos MPT. El árbol de estado de cada bloque es solo un subconjunto del grupo completo. Cada vez que se extrae o importa un nuevo bloque, se agregará un nuevo nodo MPT al grupo. Para identificar el nodo raíz en el grupo de nodos, debemos consultar el encabezado del bloque. Cada bloque contiene un campo que apunta a stateRoot, que apunta al nodo raíz del MPT (que almacena los datos de la cuenta ingresados por la dirección de cuenta 2). Esto le permite a Geth consultar la información de la cuenta, como el nonce o el saldo de cualquier dirección, utilizando el algoritmo que describimos anteriormente. Tenga en cuenta que si se trata de un contrato, el estado de la cuenta contendrá un campo storageRoot no vacío y un campo codeHash. El campo storageRoot apunta a otro nodo raíz. Sin embargo, el propósito del MPT involucrado en este momento es almacenar los datos del elemento de almacenamiento del contrato; el MPT utilizará la ranura de almacenamiento como clave y los datos originales como valor. Para almacenar el MPT en el disco, Geth eligió usar LevelDB como base de datos. Sin embargo, LevelDB es una base de datos de clave-valor que solo admite el mapeo de cadena a cadena y MPT no es un mapeo de cadena a cadena. Para resolver este problema, Geth escribe cada nodo como un par clave-valor, aplanando así el árbol de estado global: el valor hash del nodo se usa como clave y el nodo serializado se usa como valor. De esta manera, Geth puede consultar el árbol de estado de cualquier bloque, porque el campo stateRoot en el encabezado del bloque es la clave, que se puede usar para buscar el nodo MPT serializado en LevelDB (Nota del traductor: es decir, el nodo raíz de un MPT). Entonces, supongamos que inicia un nodo Geth y se conecta a la red usando el modo de sincronización rápida. Geth descargará rápidamente todos los datos del bloque, pero no realizará ninguna transacción. En poco tiempo, tendrá una cadena de bloques sin información de estado. En este punto, Geth comienza a sincronizarse desde stateRoot del bloque pivote a través del descargador de estado. El descargador de estado solicitará los datos del nodo MPT correspondientes a la clave del nodo MPT del nodo par. Después de recibir el resultado, el descargador de estado realizará un cálculo hash en los datos del nodo y verificará si el valor hash obtenido es el mismo que la clave del nodo. Si son iguales, el descargador de estado sabe que el nodo MPT es correcto y luego envía más solicitudes a cada nodo secundario del nodo MPT. Si se encuentra un nodo de hoja (que contiene un estado de cuenta serializado), el código de la cuenta y el árbol de estado se pondrán en cola para obtenerlos. Tenga en cuenta la diferencia entre el subárbol sincronizado y la entrada original. Si bien ambos descargan fragmentos arbitrarios de datos, si el sincronizador espera sincronizar el árbol original, analiza esos datos en un nodo de árbol y comienza a sincronizar sus elementos secundarios. Por otro lado, si el sincronizador espera sincronizar entradas sin procesar, escribe el bloque de datos en la base de datos y termina. También tenga en cuenta que no es raro que Geth quiera enviar una solicitud al mismo nodo varias veces. Por ejemplo, si dos contratos almacenan los mismos datos, su stateRoot puede ser el mismo y también es posible que dos cuentas tengan el mismo estado de cuenta. En estos casos, Geth no quiere inundar la red con estas solicitudes, por lo que las fusionará. Sin embargo, el sincronizador no combinará el atributo sin procesar de la solicitud. Esto significa que si ya hay una solicitud de elemento original pendiente, pero el sincronizador programa una solicitud de subárbol con el mismo valor hash, este último se fusionará y el resultado final seguirá siendo solo una solicitud de elemento original. Tenga en cuenta que las solicitudes de entrada sin procesar no procesan nodos para sincronizar los nodos secundarios (a diferencia de las solicitudes de subárbol). Esto significa que si de alguna manera podemos causar un conflicto entre la entrada original y el nodo del subárbol, podemos hacer que Geth sincronice un árbol de estado incompleto. Además, Geth no saldrá (informará un error) cuando encuentre un nodo de árbol que no existe localmente, lo que equivale a suponer que si el descargador informa que la sincronización es exitosa, esta situación (datos de estado faltantes locales) no sucederá. . Esto significa que un nodo Geth que carece de un nodo de árbol se comporta de forma muy diferente a otros nodos de árbol totalmente sincronizados. Entonces, ¿cómo provocar un conflicto? Resulta ser muy simple: simplemente implementamos otro contrato con la raíz de estado serializada de un contrato que controlamos, por lo que el hash del código del contrato debe ser el mismo que el hash de raíz de estado (del contrato que controlamos), Esto significa que si el código del contrato se sincroniza primero, el árbol de estado de otro contrato no se descargará por completo. Si alguien explota esta vulnerabilidad para hacer el mal, tomará múltiples pasos y esperará mucho tiempo. Primero, implementamos un contrato (usaremos la laguna para sobrescribir el árbol de estado de este contrato). Este contrato debe tener un stateRoot único, para evitar la sincronización temprana de los nodos MPT relacionados con este stateRoot. Ahora hemos terminado. Cuando los nuevos nodos Geth se unan a la red mediante sincronización rápida, primero solicitarán el contrato Exploit para sincronizar su código y subárbol de estado. Cuando se sincroniza el código del contrato de Exploit, se crea una solicitud de entrada sin formato que se parece exactamente a la solicitud raíz de estado de Discrepancia, pero no se trata como una solicitud de subárbol. Esto significa que el nodo nunca descargará la prueba de estado de discrepancia, por lo que las solicitudes futuras para leer magia devolverán 0 en lugar de 1. Después de que haya transcurrido suficiente tiempo, todo lo que tenemos que hacer es llamar a Hardfork.hardfork (discrepancia). Cada nodo que sincronice correctamente toda la red verá una transacción revertida, mientras que cada nodo Geth que se una a la red mediante sincronización rápida verá una transacción exitosa. Esto dará como resultado dos raíces de estado diferentes para un bloque, lo que significa que podemos activar divisiones de cadena a voluntad. El equipo de Geth resolvió rápidamente el ataque al manejar el error de lectura del árbol en PR #21039 y luego corrigió completamente la vulnerabilidad al diferenciar entre la parte del código y la parte del árbol en PR #21080. Esta es una vulnerabilidad muy interesante que permite a un atacante colocar una "bomba" en la red Ethereum y detonarla en cualquier momento, lo que hace que todos los nodos Geth que usan sincronización rápida se bifurquen desde la red principal. Esta trampa explota una lógica extremadamente compleja en el código de sincronización y almacenamiento de datos de Geth, por lo que probablemente pasó desapercibida durante mucho tiempo. Estén atentos al tercer y último artículo de esta serie. En esta publicación, exploraremos los últimos errores en el cliente Geth, sin revelar los detalles. Técnicamente, los nodos de valor en Geth no incluyen sufijos. Puede considerarlo como un nodo de extensión seguido de un nodo de valor (que contiene solo los datos sin procesar). De hecho, Geth usa un "trie seguro", es decir, todas las claves se codifican a través del algoritmo SHA-3 para garantizar que todas las claves tengan una longitud fija.
Tags:
Golden Finance informó que, según noticias del 25 de junio, el congreso de El Salvador aprobó la propuesta del presidente sobre bitcoin el miércoles, hora local.
En primer lugar, mire la tendencia del mercado alcista de BTC en 2013. Según la investigación.
En términos del establecimiento de contratos inteligentes de token ERC20, el uso de protocolos DeFi y las grandes transacciones de monedas estables.
Esta publicación es la segunda de una serie que explica un error que encontré en el cliente go-ethereum (Geth). Si aún no lo entiende.
Bitcoin ha perdido casi el 50% de sus ganancias desde que alcanzó un máximo histórico de $64,918 en abril. Los precios de otras altcoins incluso se han reducido a más de la mitad.
Descubrimos que las tecnologías emergentes futuristas volverán a la visión de la industria con una actitud muy fuerte después de un período de inactividad. Este año, el más obvio es Metaverse. En la actualidad.
Uno de los desafíos con la compatibilidad con versiones anteriores en el diseño actual de Ethereum es que el acceso al historial de la cadena de bloques requiere la verificación de EVM de las pruebas de Merkle.