Ao falar sobre minerar criptomoedas, com Python ou outra linguagem, é comum pensar que se trata de algo muito difícil de implementar. Na verdade a implementação é simples, porém sua execução é extremamente pesada e requer um hardware potente.
O interpretador Python não possui a alta performance como principal característica sendo, portanto, inadequado para a execução dos cálculos pesados que a mineração de criptomoedas requer. Em contrapartida, é uma excelente linguagem para o aprendizado deste tema graças a sua simplicidade.
Através de um código fictício que simula minerar a moeda bitcoin com Python, vamos entender o que são códigos de hash criptográficos, o que é uma blockchain e, em termos gerais, como funciona a rede do bitcoin.
O que um código de hash?
Um código de hash nada mais é que o resultado de uma transformação matemática de uma entrada (um texto, imagem, documento, etc) em um conjunto numérico, normalmente representado em formato hexadecimal. Existem várias funções matemática que desempenham tal transformação, no entanto, para o nosso exemplo, usaremos apenas função SHA256.
A função SHA256 gera códigos criptográficos de 256 bits, ou seja, uma sequência de 256 zeros e uns que, para simplificar, costuma aparecer em formato hexadecimal. Como resultado, seu tamanho cai para uma sequência de 64 caracteres variando de 0 à 9 e de A à F.
Assim sendo, nada melhor que um trecho de código para exemplificar. Imagine que queremos gerar o código de hash da palavra “Mochileiro”:
import hashlib
# Texto de entrada
texto = "Mochileiro"
# Criar o objeto hash SHA-256
hash_obj = hashlib.sha256(texto.encode('utf-8'))
print("SHA-256 Hash:", hash_obj.hexdigest())
O trecho acima, independente de quantas vezes o executamos, sempre resulta na seguinte saída hexadecimal:
SHA-256 Hash: d8f2668cf846d80f00b254e319d8d78bd9b8427525a64b812593a11ebce957cb
Do mesmo modo, se apenas trocarmos a primeira letra de “Mochileiro” para “mochileiro”, o código de hash muda totalmente:
SHA-256 Hash: 229c70af2a74113d8d0ac6da367a9cf1001bcaca95c9fab1aed154feba3fe96c
Em suma, uma função (ou algorítmo) de hash sempre gera a mesma saída de tamanho fixo para a mesma entrada, gerando uma espécie de “impressão digital” do seu conteúdo.
Porém, é impossível percorrer o caminho inverso, ou seja, transformar um hash em sua entrada de origem. Portanto o processo de geração de chave hash é totalmente unidirecional.
O que é uma blockchain?
Uma blockchain (ou cadeia de blocos) é uma espécie de banco de dados seguro, que armazena informações através de blocos interligados de forma sequencial e imutável.
Em contrapartida aos bancos de dados convencionais, ela trabalha de forma descentralizada (através de “nós”), que evita a necessidade de uma autoridade central para gerenciar os dados e consequentemente aumenta a segurança.
Além disso, uma blockchain utiliza criptografia hash para garantir a autenticidade das informações, onde cada bloco possui o código hash de seu antecessor, formando assim uma cadeia segura.
No caso de blockchains públicas a transparência é uma característica predominante, ou seja, qualquer usuário pode visualizar seu conteúdo. Dessa forma, fica mais fácil a identificação de possíveis fraudes por alteração de integridade dos dados.
Um novo bloco de dados ainda precisa da validação da maioria dos “nós” participantes da rede antes da adição na blockchain. Essa validação é alcançada através dos chamados “mecanismos de consenso” como a Prova de Trabalho e a Prova de Participação.
Apesar de ser amplamente conhecida no mundo das criptomoedas, também tem aplicações em outras áreas como a de contratos inteligentes, identidade digital dentre outras.
Como funciona uma rede bitcoin
A rede bitcoin utiliza uma blockchain contendo os dados de todas as transações realizadas por seus usuários. Assim sendo, ela funciona como um livro-razão que contém o registro de todas as transações e as dispõe de forma pública, segura e imutável.
Vamos supor que um usuário queira enviar bitcoins para outro. Nesse sentido, ele realiza a transferência monetária e envia a transação para a rede bitcoin. Por sua vez, a transação chega até os nós da rede e estes verificam se a transação é válida. (se existe saldo, por exemplo)
Igualmente, outros usuários também realizam suas transações ao longo do tempo formando um conjunto de transações.
Em suma, um determinado conjunto de transações somadas ao código de hash de seu bloco antecessor compõe um novo bloco. Um bloco possui uma série de outras informações. No entanto, para fins didáticos as omitirei.
Assim que a formação de um bloco de transações termina, a mineração acontece. Em outras palavras, vários mineradores sedentos pela recompensa em bitcoins competem para resolver um problema criptográfico, também conhecido como Prova de Trabalho.
No entanto, a Prova de Trabalho não é nada fácil uma vez que o problema consiste na tentativa de gerar um hash que inicie com um número determinado de zeros à esquerda. Conforme vimos, o hash deriva de um processo unidirecional e portanto, somente através de tentativa e erro é que se consegue concluir esta tarefa.
Sendo assim, quem resolver a Prova de Trabalho primeiro, vence. No momento desta publicação, a recompensa é de 3,125 BTC, equivalente a R$ 1.669.671,28.
Por fim, quando encontrado o código de hash que satisfaça a condição de zeros à esquerda e após restante dos nós da rede validarem este código, podemos dizer que o bloco é válido (minerado) e pode ser adicionado à blockchain.
Prova de Trabalho para Minerar com Python
O problema criptográfico consiste em encontrar um número que, quando concatenado com as informação do bloco, gere através da função de hash SHA256 uma representação hexadecimal que inicie com um determinado número de zeros à esquerda. Por exemplo:
# SHA256 com 5 zeros à esquerda
0000017afaed6ebe2da67d898ef563830844262b126b132f35b8b0ed2419471f
Por vezes, esse número recebe o nome de NONCE e o segredo é incrementá-lo através iterações consecutivas até atingir números estratosféricos.
Além disso, é necessário gerar uma nova chave hash para saber se esta inicia-se com a quantidade requerida de zeros à esquerda.
Finalmente, vamos minerar com Python!
import hashlib
# Simulação de um conjunto de transações fictícias
transacoes = [
{"numero": 1, "De": "Pedro", "Para": "Joao", "Valor": "1 BTC"},
{"numero": 2, "De": "Joao", "Para": "Maria", "Valor": "0,00251 BTC"},
{"numero": 3, "De": "Joao", "Para": "Jose", "Valor": "0,000414 BTC"},
{"numero": 4, "De": "Maria", "Para": "Joao", "Valor": "3,125 BTC"},
{"numero": 5, "De": "Maria", "Para": "Pedro", "Valor": "0,095 BTC"},
]
# Simulação do hash de um suposto bloco anterior
hash_anterior = '229c70af2a74113d8d0ac6da367a9cf1001bcaca95c9fab1aed154feba3fe96c'
def validar_bloco(num_bloco: int, transacoes: list, hash_bloco_ant: str, zeros: int):
nonce = 0
# Concatenção das informações do bloco em formato String
info_bloco = str(num_bloco) + str(transacoes) + hash_bloco_ant
while True:
# Adiciona o nonce ao bloco
info_bloco_nonce = info_bloco + str(nonce)
# Gera o hash em base hexadecimal
hash_atual = hashlib.sha256(info_bloco_nonce.encode('utf-8')).hexdigest()
# Checa a quantidade de zeros à equerda
if hash_atual.startswith("0"*zeros):
return nonce, hash_atual
nonce += 1
# Neste exemplo, a função procura por 6 zeros à esquerda
nonce, hash_encontrado = validar_bloco(1, transacoes, hash_anterior, 5)
print(nonce, hash_encontrado)
O código acima é bastante simples e consiste em apenas somar o valor de NONCE a cada iteração, concatená-lo à string de representação do bloco, gerar um novo hash e verificar se este hash inicia com cinco zeros.
A complexidade de execução aumenta a medida que a quantidade de zeros necessária à esquerda também aumenta. Em um hardware comum, enquanto um exemplo como este de apenas cinco zeros leva alguns segundos de execução, outro exemplo com dez zeros pode levar muitas horas.
Atualmente o número de zeros requerido é de aproximadamente vinte, podendo variar para mais ou menos. Sendo assim, já podemos ter uma ideia do quão bizarro pode ser descobrir o NONCE.
Caso tenha curiosidade, você pode encontrar aqui dados reais dos últimos blocos bitcoin minerados como por exemplo o número do bloco, hash gerado, nonce encontrado e mais.
Conclusão
O algoritmo que implementa a Prova de Trabalho é muito simples, no entanto sua execução é extremamente pesada. Embora mais adequado, o uso de linguagens mais performáticas como C++ ou Rust não dispensa o uso de um hardware pesado com suporte a placas de vídeo robustas.
O código demonstrado aqui para “minerar” bitcoin com Python é fictício e tem caráter didático. Mesmo assim é uma ótima forma que compreender o básico da infraestrutura que suporta a tecnologia das criptomoedas.
Além disso, vale ressaltar que cada criptomoeda tem suas próprias características e podem, desta forma, ter diferentes algoritmos de criptografia, prova de trabalho, protocolos de comunicação e assim por diante.
Minerar criptos não é nada fácil. Descobrir o NONCE é praticamente o mesmo que acertar na loteria para nós, pobres mortais. Mesmo assim, se você deseja investir nisso, já existem softwares que realizam a mineração de forma otimizada.
Algum exemplos são o CGMiner e o EasyMiner.
Espero ter ajudado!
Até a próxima!