Como criar um Blockchain em Python

Os Blockchains são sistemas de registo distribuídos, imutáveis e descentralizados. Eles são amplamente utilizados em várias aplicações, como criptomoedas, votação eletrónica, cadeias de suprimentos, entre outros.
Criar um Blockchain do zero pode parecer intimidante, mas é uma excelente maneira de entender como eles funcionam e como eles podem ser implementados em suas próprias aplicações.
Neste artigo, vamos criar um Blockchain em Python usando a biblioteca Flask. Antes de começar, é importante ter conhecimento básico em Python, bem como em hash e criptografia.
A primeira coisa que precisamos fazer é importar as bibliotecas necessárias. Usaremos o módulo datetime para obter a hora atual, o módulo hashlib para criar hashes e o módulo json para serializar nossos dados em formato JSON.
import datetime
import hashlib
import json
from flask import Flask, jsonify
Em seguida, definimos a classe Blockchain. O construtor da classe inicializa a nossa cadeia com um bloco de génese, que tem um índice 1, um carimbo de data/hora atual, um número de prova (que explicaremos mais adiante) e um hash anterior de valor zero.
class Blockchain:
def __init__(self):
self.chain = []
self.create_block(proof=1, previous_hash='0')
Em seguida, criamos um método chamado create_block()
para criar novos blocos. Este método recebe a prova atual e o hash anterior, e cria um dicionário contendo as informações do bloco, como índice, carimbo de data/hora, número de prova e hash anterior.
Em seguida, adicionamos o bloco recém-criado à nossa cadeia.
def create_block(self, proof, previous_hash):
block = {'index': len(self.chain) + 1,
'timestamp': str(datetime.datetime.now()),
'proof': proof,
'previous_hash': previous_hash}
self.chain.append(block)
return block
O método print_previous_block
retorna o último bloco da cadeia.
def print_previous_block(self):
return self.chain[-1]
O método proof_of_work
recebe um valor de prova anterior e retorna um novo valor de prova que satisfaça a condição de ser um hash com quatro zeros à esquerda.
def proof_of_work(self, previous_proof):
new_proof = 1
check_proof = False
while check_proof is False:
hash_operation = hashlib.sha256(str(new_proof ** 2 - previous_proof ** 2).encode()).hexdigest()
if hash_operation[:4] == '0000':
check_proof = True
else:
new_proof += 1
return new_proof
O método hash
recebe um bloco e retorna seu hash. O bloco é codificado em JSON e em seguida é passado por um hash SHA256.
def hash(self, block):
encoded_block = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(encoded_block).hexdigest()
Para garantir a integridade da blockchain, é importante que cada bloco seja validado antes de ser adicionado à cadeia. O método chain_valid
faz justamente essa validação. Ele recebe como parâmetro uma cadeia de blocos e verifica se ela é válida.
def chain_valid(self, chain):
previous_block = chain[0]
block_index = 1
while block_index < len(chain):
block = chain[block_index]
if block['previous_hash'] != self.hash(previous_block):
return False
previous_proof = previous_block['proof']
proof = block['proof']
hash_operation = hashlib.sha256(str(proof ** 2 - previous_proof ** 2).encode()).hexdigest()
if hash_operation[:4] != '0000':
return False
previous_block = block
block_index += 1
return True
O método começa definindo o bloco anterior como o primeiro bloco na cadeia e define a variável block_index
como 1. Em seguida, o método itera por toda a cadeia a partir do segundo bloco, verificando se o bloco atual é válido em relação ao bloco anterior.
Para verificar a validade, o método checa se o previous_hash
do bloco atual é igual ao hash do bloco anterior, gerado pelo método hash()
. Se essa condição não for satisfeita, a cadeia é considerada inválida e o método retorna False
.
O método também verifica se o proof
do bloco atual é válido, ou seja, se a operação de hash realizada a partir do proof
e do previous_proof
começa com quatro zeros. Essa verificação é feita através da variável hash_operation
, que é gerada pela operação de hash sha256.
Caso a validação do bloco atual seja bem-sucedida, o método define o bloco atual como o bloco anterior e incrementa a variável block_index
em 1.
Por fim, se a cadeia inteira for validada com sucesso, o método retorna True
.
Flask
O Flask é um framework web escrito em Python que permite criar aplicações web rapidamente. Ele é usado neste exemplo para fornecer uma interface HTTP para a blockchain criada. O Flask expõe endpoints que podem ser acessados através de uma URL específica.
No código abaixo, a aplicação Flask é inicializada e uma instância da blockchain é criada:
app = Flask(__name__)
blockchain = Blockchain()
Em seguida, são definidos três endpoints que podem ser acessados através do método GET:
pythonCopy code@app.route('/mine_block', methods=['GET'])
def mine_block():
previous_block = blockchain.print_previous_block()
previous_proof = previous_block['proof']
proof = blockchain.proof_of_work(previous_proof)
previous_hash = blockchain.hash(previous_block)
block = blockchain.create_block(proof, previous_hash)
response = {'message': 'A block is MINED',
'index': block['index'],
'timestamp': block['timestamp'],
'proof': block['proof'],
'previous_hash': block['previous_hash']}
return jsonify(response), 200
@app.route('/get_chain', methods=['GET'])
def display_chain():
response = {'chain': blockchain.chain,
'length': len(blockchain.chain)}
return jsonify(response), 200
@app.route('/valid', methods=['GET'])
def valid():
valid = blockchain.chain_valid(blockchain.chain)
if valid:
response = {'message': 'The Blockchain is valid.'}
else:
response = {'message': 'The Blockchain is not valid.'}
return jsonify(response), 200
O primeiro endpoint, “/mine_block”, é responsável por minerar um novo bloco. O bloco é criado a partir do método create_block, que recebe como argumentos o proof (a prova do trabalho realizado) e o previous_hash (o hash do bloco anterior na cadeia).
Antes de criar o novo bloco, o método mine_block utiliza o método print_previous_block para recuperar o último bloco da cadeia, de modo a obter o previous_proof, que é utilizado como argumento no método proof_of_work. O método proof_of_work utiliza uma operação de hash para encontrar um valor de proof que satisfaça uma determinada condição. Neste caso, a condição é que o hash do novo bloco comece com quatro zeros (hash_operation[:4] == ‘0000’).
Após a criação do bloco, o método mine_block retorna um objeto JSON contendo as informações do bloco recém-criado: o índice do bloco na cadeia, o timestamp de sua criação, o valor da proof, e o hash do bloco anterior.
O segundo endpoint, “/get_chain”, retorna a cadeia de blocos completa. Ele utiliza o método display_chain para recuperar a cadeia e seu comprimento, e retorna um objeto JSON contendo essas informações.
O terceiro endpoint, “/valid”, verifica se a cadeia de blocos é válida utilizando o método chain_valid. Ele retorna um objeto JSON contendo uma mensagem indicando se a cadeia é válida ou não.
É possível testar o código executando o script e acessando os endpoints através de um navegador web ou utilizando ferramentas para testar APIs, como o Postman. Por exemplo, para minerar um novo bloco, basta acessar a URL http://localhost:5000/mine_block. O servidor retornará um objeto JSON contendo as informações do bloco recém-criado. Para obter a cadeia completa, acesse a URL http://localhost:5000/get_chain. Para verificar se a cadeia é válida, acesse a URL http://localhost:5000/valid.
Este artigo apresentou de forma simples como criar um blockchain em Python. Começamos por definir o conceito de blockchain e suas características, e em seguida, exploramos o código completo de implementação de um blockchain.
Discutimos cada método utilizado no código, explicando o seu papel na criação e validação de blocos. Também discutimos o processo de mineração e a utilização do algoritmo de prova de trabalho para encontrar o nonce correto e, assim, garantir a segurança do blockchain.
Além disso, exploramos a utilização do framework Flask para criar endpoints e permitir a interação com a nossa blockchain. Finalmente, apresentamos exemplos de como utilizar os endpoints criados para mineração de novos blocos, visualização da cadeia e validação do blockchain.
Para um programador, ver as coisas acontecer metendo as mãos na massa torna o processo muito mais simples e perceptível. No meu caso, antes de começar a explorar o código, tinha uma ideia de que seria algo muito mais complexo, no entanto e apesar de este exemplo ser uma versão muito simplificada do que realmente é a codificação de uma blockchain, vejo agora que não é nenhum bicho de sete cabeças, e acima de tudo deixou-me realmente curioso para o que vem a seguir.
One Response
import hashlib
import time
class Bloco:
def __init__(self, indice, timestamp, dados, hash_anterior):
self.indice = indice
self.timestamp = timestamp
self.dados = dados
self.hash_anterior = hash_anterior
self.hash = self.calcular_hash()
def calcular_hash(self):
return hashlib.sha256(
str(self.indice).encode(‘utf-8’) +
str(self.timestamp).encode(‘utf-8’) +
str(self.dados).encode(‘utf-8’) +
str(self.hash_anterior).encode(‘utf-8’)
).hexdigest()
class Blockchain:
def __init__(self):
self.chain = [self.criar_bloco_genesis()]
def criar_bloco_genesis(self):
return Bloco(0, time.time(), “Bloco Genesis”, “0”)
def obter_ultimo_bloco(self):
return self.chain[-1]
def adicionar_bloco(self, novo_bloco):
novo_bloco.hash_anterior = self.obter_ultimo_bloco().hash
novo_bloco.hash = novo_bloco.calcular_hash()
self.chain.append(novo_bloco)
if __name__ == “__main__”:
blockchain = Blockchain()
# Exemplo de uso da blockchain
bloco1 = Bloco(1, time.time(), “Dados do Bloco 1”, “”)
blockchain.adicionar_bloco(bloco1)
bloco2 = Bloco(2, time.time(), “Dados do Bloco 2”, “”)
blockchain.adicionar_bloco(bloco2)
for bloco in blockchain.chain:
print(f”Índice: {bloco.indice}”)
print(f”Timestamp: {bloco.timestamp}”)
print(f”Dados: {bloco.dados}”)
print(f”Hash Anterior: {bloco.hash_anterior}”)
print(f”Hash: {bloco.hash}”)
print(“—————————–“)