Saltar al contenido principal
Change page

Ethash

Ethash era el algoritmo de minería de prueba de trabajo (PoW) de Ethereum. La prueba de trabajo (PoW) ahora se ha apagado por completo y Ethereum ahora está asegurado usando la prueba de participación (PoS) en su lugar. Lea más sobre La Fusión, la prueba de participación (PoS) y el staking. ¡Esta página es de interés histórico!

Ethash es una versión modificada del algoritmo Dagger-Hashimoto. La prueba de trabajo (PoW) de Ethash es difícil de memoria (memory hard) (se abre en una pestaña nueva), lo que se pensaba que hacía al algoritmo resistente a los ASIC. Eventualmente se desarrollaron los ASIC para Ethash, pero la minería con GPU siguió siendo una opción viable hasta que se apagó la prueba de trabajo. Ethash todavía se usa para minar otras monedas en otras redes de prueba de trabajo que no son de Ethereum.

¿Cómo funciona Ethash?

La dificultad de memoria se logra con un algoritmo de prueba de trabajo que requiere elegir subconjuntos de un recurso fijo dependiente del nonce y el encabezado del bloque. Este recurso (de unos pocos gigabytes de tamaño) se llama DAG. El DAG se cambia cada 30000 bloques, una ventana de ~125 horas llamada época (aproximadamente 5,2 días) y tarda un tiempo en generarse. Dado que el DAG solo depende de la altura del bloque, se puede pregenerar, pero si no es así, el cliente debe esperar hasta el final de este proceso para producir un bloque. Si los clientes no pregeneran y almacenan en caché los DAG con anticipación, la red puede experimentar un retraso masivo de bloques en cada transición de época. Tenga en cuenta que el DAG no necesita ser generado para verificar la prueba de trabajo, lo que esencialmente permite la verificación con bajo uso de CPU y poca memoria.

La ruta general que toma el algoritmo es la siguiente:

  1. Existe una semilla que se puede calcular para cada bloque escaneando los encabezados de los bloques hasta ese punto.
  2. A partir de la semilla, se puede calcular un caché pseudoaleatorio de 16 MB. Los clientes ligeros almacenan el caché.
  3. A partir del caché, podemos generar un conjunto de datos de 1 GB, con la propiedad de que cada elemento en el conjunto de datos depende de solo un pequeño número de elementos del caché. Los clientes completos y los mineros almacenan el conjunto de datos. El conjunto de datos crece linealmente con el tiempo.
  4. La minería implica tomar fragmentos aleatorios del conjunto de datos y unirlos mediante hashing. La verificación se puede hacer con poca memoria utilizando el caché para regenerar las piezas específicas del conjunto de datos que necesita, por lo que solo necesita almacenar el caché.

El gran conjunto de datos se actualiza una vez cada 30000 bloques, por lo que la gran mayoría del esfuerzo de un minero será leer el conjunto de datos, no hacerle cambios.

Definiciones

Empleamos las siguientes definiciones:

El uso de 'SHA3'

El desarrollo de Ethereum coincidió con el desarrollo del estándar SHA3, y el proceso de estandarización hizo un cambio tardío en el relleno (padding) del algoritmo hash finalizado, de modo que los hashes "sha3_256" y "sha3_512" de Ethereum no son hashes sha3 estándar, sino una variante a menudo denominada "Keccak-256" y "Keccak-512" en otros contextos. Vea la discusión, por ejemplo, aquí (se abre en una pestaña nueva), aquí (se abre en una pestaña nueva) o aquí (se abre en una pestaña nueva).

Por favor, tenga esto en cuenta ya que se hace referencia a los hashes "sha3" en la descripción del algoritmo a continuación.

Parámetros

Los parámetros para el caché y el conjunto de datos de Ethash dependen del número de bloque. El tamaño del caché y el tamaño del conjunto de datos crecen linealmente; sin embargo, siempre tomamos el número primo más alto por debajo del umbral de crecimiento lineal para reducir el riesgo de regularidades accidentales que conduzcan a un comportamiento cíclico.

Las tablas de valores de tamaño del conjunto de datos y del caché se proporcionan en el apéndice.

Generación de caché

Ahora, especificamos la función para producir un caché:

El proceso de producción de caché implica primero llenar secuencialmente 32 MB de memoria, luego realizar dos pasadas del algoritmo RandMemoHash de Sergio Demian Lerner de Strict Memory Hard Hashing Functions (2014) (se abre en una pestaña nueva). La salida es un conjunto de 524288 valores de 64 bytes.

Función de agregación de datos

Usamos un algoritmo inspirado en el hash FNV (se abre en una pestaña nueva) en algunos casos como un sustituto no asociativo para XOR. Tenga en cuenta que multiplicamos el número primo con la entrada completa de 32 bits, en contraste con la especificación FNV-1 que multiplica el número primo con un byte (octeto) a la vez.

FNV_PRIME = 0x01000193

def fnv(v1, v2):
    return ((v1 * FNV_PRIME) ^ v2) % 2**32

Tenga en cuenta que, aunque el Libro Amarillo especifica fnv como v1*(FNV_PRIME ^ v2), todas las implementaciones actuales usan consistentemente la definición anterior.

Cálculo del conjunto de datos completo

Cada elemento de 64 bytes en el conjunto de datos completo de 1 GB se calcula de la siguiente manera:

Esencialmente, combinamos datos de 256 nodos de caché seleccionados pseudoaleatoriamente y aplicamos hashing a eso para calcular el nodo del conjunto de datos. Todo el conjunto de datos se genera luego mediante:

def calc_dataset(full_size, cache):
    return [calc_dataset_item(cache, i) for i in range(full_size // HASH_BYTES)]

Bucle principal

Ahora, especificamos el bucle principal tipo "hashimoto", donde agregamos datos del conjunto de datos completo para producir nuestro valor final para un encabezado y nonce en particular. En el código a continuación, header representa el hash SHA3-256 de la representación RLP de un encabezado de bloque truncado, es decir, de un encabezado excluyendo los campos mixHash y nonce. nonce son los ocho bytes de un entero sin signo de 64 bits en orden big-endian. Así que nonce[::-1] es la representación little-endian de ocho bytes de ese valor:

Esencialmente, mantenemos una "mezcla" de 128 bytes de ancho, y de forma repetida y secuencial obtenemos 128 bytes del conjunto de datos completo y usamos la función fnv para combinarlo con la mezcla. Se utilizan 128 bytes de acceso secuencial para que cada ronda del algoritmo siempre obtenga una página completa de la RAM, minimizando los fallos del búfer de traducción anticipada (TLB) que los ASIC teóricamente podrían evitar.

Si la salida de este algoritmo está por debajo del objetivo deseado, entonces el nonce es válido. Tenga en cuenta que la aplicación adicional de sha3_256 al final asegura que exista un nonce intermedio que se pueda proporcionar para demostrar que al menos se realizó una pequeña cantidad de trabajo; esta rápida verificación externa de PoW se puede utilizar con fines anti-DDoS. También sirve para proporcionar garantía estadística de que el resultado es un número imparcial de 256 bits.

Minería

El algoritmo de minería se define de la siguiente manera:

def mine(full_size, dataset, header, difficulty):
    # Rellenar con ceros el objetivo para comparar con el hash en el mismo dígito
    target = zpad(encode_int(2**256 // difficulty), 64)[::-1]
    from random import randint
    nonce = randint(0, 2**64)
    while hashimoto_full(full_size, dataset, header, nonce) > target:
        nonce = (nonce + 1) % 2**64
    return nonce

Definición del hash semilla

Para calcular el hash semilla que se utilizaría para minar sobre un bloque dado, usamos el siguiente algoritmo:

 def get_seedhash(block):
     s = '\x00' * 32
     for i in range(block.number // EPOCH_LENGTH):
         s = serialize_hash(sha3_256(s))
     return s

Tenga en cuenta que para una minería y verificación fluidas, recomendamos precalcular los futuros hashes semilla y conjuntos de datos en un hilo separado.

Lecturas adicionales

¿Conoce algún recurso de la comunidad que le haya ayudado? ¡Edite esta página y agréguelo!

Apéndice

El siguiente código debe anteponerse si está interesado en ejecutar la especificación de Python anterior como código.

Tamaños de datos

Las siguientes tablas de búsqueda proporcionan aproximadamente 2048 épocas tabuladas de tamaños de datos y tamaños de caché.