Blockchain, ou cadeia de blocos, é uma forma de armazenamento de dados. Assim como armazenamos arquivos em dispositivos como HDs, SSDs ou cartões microSD, na blockchain os dados são armazenados em blocos encadeados.
Cada bloco é conectado ao anterior por meio de um identificador único chamado hash. Sempre que um novo bloco é adicionado, ele armazena também a hash do bloco anterior, formando assim uma cadeia contínua. Se imaginarmos uma sequência de blocos, teríamos algo assim:
flowchart LR
A["Bloco A<br>🔗 Hash Anterior: <br>📄 Dados: 'Alice → Bob'<br>⏱️ Timestamp: 01/01/2025<br>🔢 Nonce: 23984<br>🧩 Hash: 00abc123"]
A --> B["Bloco B<br>🔗 Hash Anterior: 00abc123<br>📄 Dados: 'Bob → Carol'<br>⏱️ Timestamp: 01/01/2025<br>🔢 Nonce: 55110<br>🧩 Hash: 00def456"]
B --> C["Bloco C<br>🔗 Hash Anterior: 00def456<br>📄 Dados: 'Carol → Dave'<br>⏱️ Timestamp: 01/01/2025<br>🔢 Nonce: 99231<br>🧩 Hash: 00ghi789"]
A estrutura lembra uma lista ligada, mas com uma diferença fundamental: a necessidade de manter a integridade dos dados. E como fazemos isso? Com criptografia.
Quando criamos um bloco, a última informação gerada é o seu identificador, ou seja, a hash. Essa hash é calculada aplicando uma função criptográfica sobre todos os dados do bloco (inclusive a hash anterior e o nonce).
Veja um exemplo simples usando o algoritmo SHA-256:
const crypto = require('crypto')
const hash = crypto
.createHash('sha256')
.update('Cadeia de dados')
.digest('hes');
console.log(Buffer.from(hash).toString('hex'));
// 60460d905a8b5eb866797aad256229f1e553f7be0ad3c533420521747ef2b5ac🔁 Uma pequena alteração na entrada gera uma hash completamente diferente:
# SHA256
Entrada: "Cadeia de dados";
Saída: 60460d905a8b5eb866797aad256229f1e553f7be0ad3c533420521747ef2b5ac
Entrada: "cadeia de dados";
Saída: 800098a143bcd7482571a5d28b9f6cb4e3362baeb1c9d2a156dd8ca811bdf80bExistem diversos algoritmos de hash. O mais famoso no contexto de blockchain é o SHA-256, mas há outros como:
- MD5;
- SHA-1;
- SHA-2;
- SHA-128;
- SHA-256;
- Whirlpool (512 bits).
🔍 Whirlpool Um algoritmo de 512 bits, desenvolvido por pesquisadores brasileiros e belgas, e que é considerado uma opção de segurança sólida.
Esses algoritmos são unidirecionais, ou seja, não permitem reverter uma hash para descobrir os dados originais. Isso garante a imutabilidade e a integridade dos dados na blockchain.
Cada bloco contém uma hash única, que representa o conjunto de informações: dados, timestamp, nonce e hash anterior. Se alguém tentar alterar qualquer informação de um bloco, a hash dele muda — e como o próximo bloco depende da hash anterior, toda a cadeia precisaria ser recalculada. Veja:
flowchart LR
A["Bloco A<br>🔗 Hash Anterior: <br>📄 Dados: 'Alice → Bob'<br>⏱️ Timestamp: 01/01/2025<br>🔢 Nonce: 23984<br>🧩 Hash: 00abc123"]
A --> B["Bloco B<br>🔗 Hash Anterior: 00abc123<br>📄 Dados: 'Bob → Carol'<br>⏱️ Timestamp: 01/01/2025<br>🔢 Nonce: 55110<br>🧩 Hash: 00def456"]
Se o Bloco A for alterado, sua hash será diferente, tornando a hash armazenada no Bloco B inválida. Para manter a cadeia válida, todos os blocos subsequentes teriam que ser alterados — o que exige um enorme poder computacional.
A blockchain ganhou notoriedade com o boom das criptomoedas, mas suas origens remontam à década de 1970.
🔗 As Origens Criptográficas Em 1979, o cientista da computação 🔗 Ralph Merkle descreveu em sua dissertação uma estrutura que permitia vincular blocos de dados usando funções hash. Essa estrutura ficou conhecida como Árvore de Merkle, e é um dos pilares conceituais das blockchains modernas.
💡 Árvore de Merkle: uma estrutura de árvore binária onde cada nó é o hash de seus filhos, permitindo verificar rapidamente a integridade de grandes quantidades de dados.
Já em 1982, o criptógrafo 🔗 David Chaum, considerado o "avô do Bitcoin", apresentou uma dissertação descrevendo um sistema computacional confiável operado por partes que não confiam entre si — uma ideia central da blockchain como a conhecemos hoje.
A primeira descrição completa de uma blockchain funcional surgiu em 2008, no famoso whitepaper de 🔗 Satoshi Nakamoto – "Bitcoin: Um Sistema de Dinheiro Eletrônico Ponto-a-Ponto". Nele, Nakamoto propôs:
- Transações agrupadas em blocos.
- Cada transação com um hash assinado.
- Validação pública das assinaturas.
- Ligação entre blocos por meio de hashes.
Adoção de uma prova de trabalho (Proof of Work - PoW).
A PoW exige que o sistema encontre um número que, quando combinado com os dados do bloco e processado por uma função de hash (como SHA-256), gere um resultado que comece com um número pré-definido de zeros.
flowchart LR
A["Número"]
A --> B["SHA256"]
B --> C["0000aef125bc"]
C --> D["4 bits 0"]
Quanto mais zeros iniciais forem exigidos, mais difícil é encontrar esse número. Como o hash muda completamente com qualquer alteração nos dados de entrada, a única forma de encontrar o número correto é tentativa e erro.
O número que satisfaz a condição da PoW é chamado de Nonce (Number used once). Ele:
- É único para cada bloco.
- É incluído no cabeçalho do bloco.
- Não pode ser reaproveitado.
A função de mineração consiste basicamente em tentar diferentes nonces até encontrar um que gere uma hash válida (com os zeros necessários).
Esse processo é chamado de mineração. Quem encontra o nonce correto primeiro "descobre" o bloco e pode propagá-lo para a rede. Como verificar o nonce correto é simples e rápido, qualquer pessoa pode validar o bloco assim que ele for proposto.
flowchart TD
Start["⛏️ Início da Mineração"]
TryNonce["🔄 Tenta um Nonce"]
GenerateHash["🧩 Gera Hash com SHA-256"]
CheckHash["🔍 Verifica se a Hash<br>começa com 4 zeros"]
Valid["✅ Hash Válida<br>Bloco pode ser adicionado"]
Invalid["❌ Hash Inválida<br>Tenta outro Nonce"]
End["📦 Bloco Adicionado<br>à Blockchain"]
Start --> TryNonce
TryNonce --> GenerateHash
GenerateHash --> CheckHash
CheckHash -->|Sim| Valid
CheckHash -->|Não| Invalid
Invalid --> TryNonce
Valid --> End
Em uma blockchain, os dados de transações dentro de um bloco são organizados usando uma estrutura chamada Merkle Tree (ou Árvore de Merkle). Essa estrutura permite:
- Verificar se uma transação pertence a um bloco sem precisar verificar todas as outras.
- Garantir que os dados da transação não foram alterados.
- Otimizar o armazenamento e a verificação de dados.
graph TD
T1["📄 Tx1"]
T2["📄 Tx2"]
T3["📄 Tx3"]
T4["📄 Tx4"]
H1["🔗 Hash(Tx1 + Tx2)"]
H2["🔗 Hash(Tx3 + Tx4)"]
Root["🌳 Root Hash<br>(Hash(H1 + H2))"]
T1 --> H1
T2 --> H1
T3 --> H2
T4 --> H2
H1 --> Root
H2 --> Root
A Merkle Tree protege a blockchain da seguinte forma:
- Cada transação é criptografada com uma função de hash.
- As hashes são combinadas duas a duas até chegar à Root Hash, que representa todo o conjunto de transações.
- Se qualquer transação for alterada, a hash da transação muda, afetando todas as hashes subsequentes até a raiz.
Se um nó malicioso tentar modificar uma transação dentro do bloco, ele terá que:
- Recalcular a hash da transação.
- Recalcular todas as hashes intermediárias até a Root Hash.
- Criar uma nova cadeia (fork) com base nessa nova árvore de hashes.
Ou seja: ele estaria tentando criar um novo galho na blockchain a partir de uma árvore diferente. Mas para que esse novo galho seja aceito:
- Ele precisaria minerar blocos mais rápido que toda a rede (o que é computacionalmente quase impossível).
- A nova cadeia precisaria se tornar a mais longa para ser considerada válida pelos outros nós.
flowchart LR
Main1["Bloco 1 (Original)"]
Main2["Bloco 2 (Original)"]
Main3["Bloco 3 (Original)"]
Fork2["🚨 Bloco 2 (Fraudado)"]
Fork3["🚨 Bloco 3 (Fraudado)"]
Main1 --> Main2 --> Main3
Main1 --> Fork2 --> Fork3
Graças à estrutura em árvore de hashes:
- A integridade de cada transação pode ser verificada individualmente.
- A tentativa de fraude é detectável e praticamente inviável.
📚 Essa estrutura foi descrita pela primeira vez por Ralph Merkle em 1979 e é um dos pilares da segurança da blockchain.
Nesse projeto existem apenas 3 arquivos: src/index.ts arquivo onde iniciamos nossa block chain, src/helpers.ts arquivo onde colocamos funções comuns no sistema e src/blockchain.ts onde implementamos nossa blockchain.
A classe Blockchain representa uma cadeia de blocos com suporte a Proof of Work (PoW). Cada bloco é composto por um cabeçalho com um hash e nonce, e um payload com os dados e informações de sequência.
new Blockchain(difficulty?: number)- difficulty (opcional): Número de zeros com os quais o hash deve começar para ser considerado válido. Valor padrão: 4.
getChain: Block[]
Retorna todos os blocos da blockchain.
createBlock(data: any): Block["payload"]
Cria um novo payload de bloco com os dados fornecidos.
data: Dados genéricos que serão armazenados no bloco.- Retorna o payload pronto para ser minerado.
mineBlock(payload: Block["payload"]): Block
Realiza a mineração do bloco, encontrando um nounce válido que satisfaz a dificuldade.
payload: O conteúdo do bloco a ser minerado.- Retorna o bloco completo com header e payload.
verifyBlock(block: Block): boolean
Valida se o bloco é consistente com a blockchain atual.
- Verifica se o
previousHashconfere com o último bloco. - Valida se o
nouncerealmente gera o hash esperado. - Retorna true se o bloco for válido.
addBlock(block: Block): Block[]
Adiciona um bloco à cadeia após verificar sua validade.
- Retorna a cadeia de blocos atualizada.
interface Block {
header: {
nounce: number;
hash: string;
},
payload: {
sequence: number;
timestamp: number;
data: any;
previousHash: string;
}
}Ao iniciar a blockchain, o primeiro bloco é automaticamente criado com o nome Genesis Block, sem previousHash.
A mineração é baseada no algoritmo PoW: um nounce é incrementado até que o hash resultante do payload mais esse número comece com n zeros, de acordo com a dificuldade.
Antes de iniciar, certifique-se de ter o Node.js instalado na sua máquina.
- Instale as dependências
npm install- Compile o projeto
npm run build- Execute o projeto
A aplicação pode receber dois parâmetros:
dificuldade: número de zeros que o hash final deve conter no início (ex: 2, 3, 4...)
blocos: número de blocos que devem ser minerados (ex: 5, 10, 20...)
npm run start -- [dificuldade] [blocos]Exemplo: Rodando com dificuldade 3 e minerando 5 blocos:
npm run start -- 3 5Esse projeto foi implementado seguindo o vídeo do 🔗 Lucas Santos