Pular para o conteúdo principal
Change page

Ethash

Ethash foi o algoritmo de mineração da prova de trabalho do Ethereum. A prova de trabalho foi totalmente desativada e o Ethereum agora é protegido usando a prova de participação em vez disso. Leia mais sobre The Merge, proof-of-stake e staking. Esta página é de interesse histórico!

Ethash é uma versão modificada do algoritmo Dagger-Hashimoto. A prova de trabalho do Ethash tem uso intensivo de memória (opens in a new tab), o que se pensava que tornaria o algoritmo resistente a ASICs. Os ASICs Ethash foram eventualmente desenvolvidos, mas a mineração de GPU ainda era uma opção viável até que a prova de trabalho fosse desativada. Ethash ainda é usado para minerar outras moedas em outras redes de prova de trabalho não Ethereum.

Como o Ethash funciona?

Dificuldade de memória é alcançada com um algoritmo de prova de trabalho que requer a escolha de subconjuntos de um recurso fixo dependente do nonce e do cabeçalho do bloco. Este recurso (alguns gigabytes em tamanho) é chamado de DAG. O DAG é alterado a cada 30.000 blocos, uma janela de cerca de 125 horas chamada de período eletrônico (aproximadamente 5,2 dias) e leva um tempo para gerar. Como o DAG depende apenas da altura do bloco, ele pode ser pré-gerado, mas o cliente não precisa esperar até o final deste processo para produzir um bloco. Se os clientes não pré-geraram e armazenaram em cache os DAGs antes, a rede pode sofrer um grande atraso em blocos em cada transição de período eletrônico (epoch). Note que o DAG não precisa ser gerado para verificar a prova de trabalho, permitindo essencialmente a verificação com baixa CPU e pouca memória.

A rota geral que o algoritmo faz é a seguinte:

  1. Existe uma seed que pode ser calculada para cada bloco, escaneando os cabeçalhos do bloco até esse ponto.
  2. A partir da seed, pode-se calcular um cache pseudoaleatório de 16 MB. Clientes leves armazenam o cache.
  3. A partir do cache, podemos gerar um conjunto de dados de 1 GB, com a propriedade de que cada item no conjunto de dados depende de apenas um pequeno número de itens do cache. Clientes e mineradores completos armazenam o conjunto de dados. O conjunto de dados cresce linearmente com o tempo.
  4. Mineração envolve pegar fatias aleatórias do conjunto de dados e fazer hashing deles juntos. A verificação pode ser feita com pouca memória usando o cache para regenerar os pedaços específicos do conjunto de dados que você precisa, então você só precisa armazenar o cache.

O grande conjunto de dados é atualizado uma vez a cada 30.000 blocos, então o maior esforço de um minerador é ler o conjunto de dados, e não fazer alterações nele.

Definições

Nós empregamos as seguintes definições:

O uso de 'SHA3'

O desenvolvimento do Ethereum coincidiu com o desenvolvimento do padrão SHA3, e o processo de padrões fez uma alteração tardia no preenchimento do algoritmo de hash finalizado, para que os hashes "sha3_256" e "sha3_512" do Ethereum não sejam hashes sha3 padrão, mas uma variante muitas vezes referida como "Keccak-256" e "Keccak-512" em outros contextos. Veja a discussão, p. ex., aqui (opens in a new tab), aqui (opens in a new tab), ou aqui (opens in a new tab).

Tenha isso em mente, já que hashes "sha3" são referidos na descrição do algoritmo abaixo.

Parâmetros

Os parâmetros do cache Ethash e do conjunto de dados dependem do número do bloco. Tamanho do cache e tamanho do conjunto de dados crescem linearmente; entretanto, sempre tomamos o mais alto prime abaixo do limiar de crescimento linear, a fim de reduzir o risco de regularidades acidentais que conduzem a comportamentos cíclicos.

Tabelas de conjunto de dados e valores de tamanho do cache são fornecidos no apêndice.

Geração de cache

Agora, especificamos a função para produzir um cache:

O processo de produção de cache envolve primeiro preencher sequencialmente 32 MB de memória e, em seguida, realizar duas passagens do algoritmo RandMemoHash de Sergio Demian Lerner de Strict Memory Hard Hashing Functions (2014) (opens in a new tab). A saída é um conjunto de 524288 valores de 64-bytes.

Função de agregação de dados

Usamos um algoritmo inspirado no hash FNV (opens in a new tab) em alguns casos como um substituto não associativo para XOR. Observe que multiplicamos o primo com a entrada completa de 32 bits, em contraste com a especificação FNV-1 que multiplica o primo por um byte (octeto) por sua vez.

FNV_PRIME = 0x01000193

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

Observe que até mesmo o yellow paper especifica fnv como v1*(FNV_PRIME ^ v2). Todas as implementações atuais usam consistentemente a definição acima.

Cálculo completo do conjunto de dados

Cada item de 64 bytes no conjunto de dados completo de 1 GB é calculado da seguinte forma:

Essencialmente, combinamos dados de 256 nós de cache selecionados de maneira pseudo-aleatória e fazemos o hash para calcular o nó do conjunto de dados. Todo o conjunto de dados é então gerado por:

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

Loop principal

Agora, especificamos o loop padrão "hashimoto" principal, onde agregamos dados do conjunto de dados completo para produzir nosso valor final para um cabeçalho em particular ou nonce. No código abaixo, header representa o hash SHA3-256 da representação RLP de um cabeçalho de bloco truncado, ou seja, de um cabeçalho que exclui os campos mixHash e nonce. nonce são os oito bytes de um inteiro sem sinal de 64 bits em ordem big-endian. Então, nonce[::-1] é a representação little-endian de oito bytes desse valor:

Essencialmente, mantemos um "mix" de 128 bytes de largura e, de maneira sequencial e repetida, buscamos 128 bytes do conjunto de dados completo e usamos a função fnv para combiná-lo com o mix. 128 bytes de acesso sequencial são usados para que cada rodada do algoritmo sempre busque uma página inteira de RAM, minimizando a possibilidade de que o buffer de pesquisa de tradução perca o que os ASICs teoricamente seriam capazes de evitar.

Se a saída deste algoritmo está abaixo do alvo desejado, então o nonce é válido. Observe que a aplicação extra de sha3_256 no final garante que existe um nonce intermediário que pode ser fornecido para provar que pelo menos uma pequena quantidade de trabalho foi feita; esta verificação rápida de PoW externa pode ser usada para fins anti-DDoS. Serve também para dar garantias estatísticas de que o resultado é um número imparcial de 256 bits.

Mineração

O algoritmo de mineração é definido da seguinte forma:

def mine(full_size, dataset, header, difficulty):
    # preencher com zeros o alvo para comparar com o hash no mesmo 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

Definindo o hash da seed

Para calcular o hash seed que seria usado para minerar no topo de um determinado bloco, usamos o seguinte algoritmo:

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

Observe que, para que a mineração e a verificação aconteçam sem contratempos, recomendamos pré-computar os hashes seed e conjuntos de dados futuros em threads separadas.

Leitura adicional

Conhece um recurso da comunidade que o ajudou? Edite esta página e adicione-a!

Apêndice

O código a seguir deve ser precedido se você estiver interessado em executar a especificação python acima como código.

Tamanhos dos Dados

As tabelas de pesquisa a seguir fornecem aproximadamente 2.048 períodos eletrônicos (epoch) tabulados de tamanhos de dados e tamanhos de cache.

Última atualização da página: 15 de abril de 2026

Este artigo foi útil?