Voltar para o blog

Como Construí o HashDocs: Arquitetura de uma Plataforma Blockchain

Hendel Santos
8 de dezembro de 2025
8 min read

Como Construí o HashDocs: Arquitetura de uma Plataforma Blockchain

Criar uma plataforma de certificação blockchain que seja rápida, segura e escalável não é trivial. Neste post, compartilho as decisões de arquitetura, desafios e aprendizados ao construir o HashDocs.

🎯 O Problema a Resolver

Antes de falar de tecnologia, vamos ao problema:

Como criar um sistema que:

  1. Processe arquivos de qualquer tamanho (até GBs)
  2. Gere fingerprints criptográficos únicos
  3. Registre na blockchain de forma confiável
  4. Seja rápido (< 5 segundos end-to-end)
  5. Não armazene arquivos (privacidade/LGPD)
  6. Seja verificável por qualquer pessoa

🏗️ Decisões de Arquitetura

Princípio #1: Separação de Responsabilidades

Dividi o sistema em 4 camadas independentes:

┌─────────────────────────────────────┐
│   Frontend (Next.js)                │  ← Interface do usuário
├─────────────────────────────────────┤
│   Backend (Python/FastAPI)          │  ← Orquestração
├─────────────────────────────────────┤
│   Engine (Rust)                     │  ← Processamento pesado
├─────────────────────────────────────┤
│   Blockchain (Solidity/Polygon)     │  ← Imutabilidade
└─────────────────────────────────────┘

Por quê?

  • Cada camada faz uma coisa bem feita
  • Posso escalar horizontalmente cada parte
  • Bugs em uma camada não afetam outras
  • Posso trocar tecnologias sem reescrever tudo

Princípio #2: Performance Crítica

Desafio: Processar arquivos de 1GB sem consumir 1GB de RAM.

Solução: Streaming + Rust

// Conceito (simplificado)
fn process_file_stream(path: &Path) -> Result<Hash> {
    let file = File::open(path)?;
    let mut hasher = Sha256::new();
    let mut buffer = [0u8; 8192]; // 8KB buffer
    
    loop {
        let bytes_read = file.read(&mut buffer)?;
        if bytes_read == 0 { break; }
        hasher.update(&buffer[..bytes_read]);
    }
    
    Ok(hasher.finalize())
}

Resultado:

  • Arquivo de 1GB: ~50MB de RAM
  • Tempo de processamento: ~2 segundos

Princípio #3: Segurança em Camadas

Não confie em nada. Valide tudo.

Camada 1: Frontend

// Validação no cliente
if (file.size > 100_000_000) {
    throw new Error("Arquivo muito grande")
}
if (!ALLOWED_TYPES.includes(file.type)) {
    throw new Error("Tipo não permitido")
}

Camada 2: Backend

# Validação no servidor
if not is_valid_file(file):
    raise HTTPException(400, "Arquivo inválido")

# Processar sem armazenar
fingerprint = engine.process_stream(file)
# Arquivo descartado aqui ↑

Camada 3: Blockchain

// Validação on-chain
require(hash != bytes32(0), "Hash invalido");
require(proofs[hash].timestamp == 0, "Ja registrado");

🔧 Stack Tecnológico (e Por Quê)

Frontend: Next.js 14

Por quê Next.js?

  • ✅ SSR/SSG para SEO
  • ✅ App Router (rotas dinâmicas)
  • ✅ API Routes (backend leve)
  • ✅ Otimização automática

Alternativas consideradas:

  • React puro: Sem SSR
  • Vue/Nuxt: Menos ecossistema
  • Svelte: Menos maduro

Backend: Python + FastAPI

Por quê Python?

  • ✅ Rápido para desenvolver
  • ✅ Integração fácil com Rust (PyO3)
  • ✅ Ecossistema blockchain maduro (web3.py)
  • ✅ FastAPI = performance + tipagem

Alternativas consideradas:

  • Node.js: Menos performance para I/O pesado
  • Go: Mais verboso, menos libs blockchain
  • Rust puro: Overkill, desenvolvimento mais lento

Engine: Rust

Por quê Rust?

  • ✅ Performance C/C++ com segurança
  • ✅ Zero-cost abstractions
  • ✅ Sem garbage collector (previsível)
  • ✅ Compilável para Python extension

Código crítico em Rust:

  • Hashing de arquivos
  • Validação de integridade
  • Operações criptográficas

Alternativas consideradas:

  • C/C++: Menos seguro
  • Python puro: 10-100x mais lento
  • Go: GC pode causar latência

Blockchain: Polygon

Por quê Polygon?

  • ✅ EVM compatible (Ethereum)
  • ✅ Gas fees baixíssimos (~$0.001)
  • ✅ Finalidade rápida (~2s)
  • ✅ Rede madura e estável

Alternativas consideradas:

  • Ethereum: Gas fees proibitivos ($5-50)
  • Solana: Não EVM, menos ferramentas
  • BSC: Mais centralizado

🧠 Decisões Técnicas Importantes

1. Double Hashing com Size Binding

Problema: Colisões de hash (teoricamente possíveis).

Solução: Esquema proprietário

RobustFingerprint = SHA256(SHA256(Content) || FileSize)

Por quê?

  • Duas camadas de SHA-256
  • Size binding previne ataques de extensão
  • Probabilidade de colisão: ~2^-256 (impossível)

2. Web2.5 Model (Não Web3 Puro)

Decisão controversa: Usuário não paga gas.

Modelo:

  • Sistema tem wallet próprio
  • Sistema paga gas por usuários
  • Usuário paga via fiat/subscription (futuro)

Por quê?

  • ✅ UX melhor (sem MetaMask)
  • ✅ Onboarding mais fácil
  • ✅ Escalável para empresas
  • ⚠️ Mais centralizado (trade-off aceito)

3. Zero File Retention

Princípio: Nunca armazenar arquivos.

Implementação:

# Arquivo processado em memória
async def process_upload(file: UploadFile):
    # Stream direto para engine
    fingerprint = await engine.process(file.file)
    
    # Arquivo NÃO é salvo
    # Apenas fingerprint vai para blockchain
    
    return {"fingerprint": fingerprint}

Por quê?

  • ✅ LGPD compliant
  • ✅ Sem custos de storage
  • ✅ Sem risco de vazamento
  • ✅ Escalável infinitamente

4. Monorepo Structure

Estrutura:

hashdocs/
├── frontend/     # Next.js
├── backend/      # FastAPI
├── engine/       # Rust
├── contracts/    # Solidity
└── docs/         # Documentação

Por quê?

  • ✅ Versionamento unificado
  • ✅ Deploys atômicos
  • ✅ Compartilhamento de tipos
  • ✅ Mais fácil de manter

🚀 Fluxo Completo (Simplificado)

Upload de Documento

1. Usuário faz upload (Frontend)
   ↓
2. Multipart POST para Backend
   ↓
3. Backend valida e chama Engine (Rust)
   ↓
4. Engine processa stream e retorna hash
   ↓
5. Backend envia transação para Polygon
   ↓
6. Blockchain confirma e retorna tx hash
   ↓
7. Backend retorna certificado para Frontend
   ↓
8. Usuário recebe link de verificação

Tempo total: 2-5 segundos

Verificação de Documento

1. Usuário acessa link de verificação
   ↓
2. Frontend busca prova no Backend
   ↓
3. Backend consulta Smart Contract
   ↓
4. Retorna: hash, timestamp, tx hash
   ↓
5. Frontend exibe certificado

Tempo total: < 1 segundo

📊 Métricas de Performance

Benchmarks Reais

| Operação | Tempo | Memória | |----------|-------|---------| | Hash 10MB | 0.1s | 50MB | | Hash 100MB | 0.8s | 50MB | | Hash 1GB | 2.5s | 50MB | | Registro blockchain | 2-3s | - | | Verificação | 0.5s | - |

Capacidade

  • Uploads simultâneos: 100+ (com 1 CPU)
  • Throughput: 500 MB/s (SSD)
  • Custo por registro: $0.001 (gas)

🔐 Modelo de Segurança

Camadas de Proteção

  1. Input Validation: Frontend + Backend
  2. Rate Limiting: 10 uploads/minuto/IP
  3. File Streaming: Sem persistência
  4. Cryptographic Hashing: SHA-256 duplo
  5. Blockchain Immutability: Polygon

Conformidade LGPD

  • ✅ Não armazena dados pessoais
  • ✅ Não armazena arquivos
  • ✅ Processamento efêmero
  • ✅ Auditável publicamente
  • ✅ Portabilidade de dados

🎓 Lições Aprendidas

1. Rust Vale a Pena

Inicialmente considerei Python puro. Rust adicionou complexidade, mas:

  • 10-50x mais rápido para hashing
  • Uso de memória constante
  • Bugs detectados em compile-time

2. Blockchain Não é Banco de Dados

Tentei armazenar metadados on-chain. Erro!

  • Gas fees explodem
  • Dados imutáveis (não pode corrigir)
  • Lentidão

Solução: Blockchain apenas para hash + timestamp.

3. UX > Pureza Técnica

Web3 puristas criticam o modelo Web2.5. Mas:

  • Usuários não querem MetaMask
  • Empresas não querem gerenciar wallets
  • Simplicidade vence

4. Open Source Gera Confiança

Código aberto foi decisão estratégica:

  • Auditabilidade
  • Contribuições da comunidade
  • Marketing orgânico
  • Confiança de empresas

🔮 Próximos Passos Técnicos

Curto Prazo

  • [ ] API pública para integrações
  • [ ] SDK JavaScript/Python
  • [ ] Webhooks para notificações
  • [ ] Suporte a múltiplas blockchains

Médio Prazo

  • [ ] Batch processing (múltiplos arquivos)
  • [ ] Verificação off-chain (IPFS)
  • [ ] Smart contracts upgradeable
  • [ ] Layer 2 (zkSync/Optimism)

Longo Prazo

  • [ ] Descentralização completa (DAO)
  • [ ] Provas zero-knowledge
  • [ ] Cross-chain verification
  • [ ] Tokenização de certificados (NFTs)

💡 Dicas para Quem Quer Construir Algo Similar

1. Comece Simples

Minha v1 era Python puro + Ethereum Sepolia:

  • Sem Rust
  • Sem otimizações
  • Apenas prova de conceito

Aprendi fazendo. Depois refatorei.

2. Escolha a Blockchain Certa

Não use Ethereum mainnet para testes:

  • Use testnets (Sepolia, Mumbai)
  • Depois migre para Polygon/BSC
  • Só use Ethereum se necessário

3. Não Reinvente a Roda

Bibliotecas que uso:

  • Hashing: RustCrypto
  • Blockchain: web3.py / ethers.js
  • API: FastAPI
  • Frontend: Next.js + shadcn/ui

4. Monitore Tudo

Ferramentas essenciais:

  • Logs: Estruturados (JSON)
  • Métricas: Prometheus
  • Errors: Sentry
  • Blockchain: Polygonscan

5. Pense em Custos

Gas fees podem matar seu projeto:

  • Polygon: $0.001/tx ✅
  • Ethereum: $5-50/tx ❌

Para 1.000 registros/dia:

  • Polygon: $1/dia
  • Ethereum: $5.000-50.000/dia

🎯 Conclusão

Construir o HashDocs foi um desafio técnico fascinante. As decisões de arquitetura foram guiadas por três princípios:

  1. Performance: Rust para operações críticas
  2. Simplicidade: Web2.5 para melhor UX
  3. Segurança: Zero file retention + blockchain

O resultado é uma plataforma que:

  • Processa GBs em segundos
  • Custa centavos por registro
  • É auditável e open-source
  • Escala horizontalmente O código deixei privado no github pois estou alterando as versões e não decidi o modo de contribuição.

Perguntas técnicas? Deixe nos comentários ou entre em contato comigo.

Leia também:

Compartilhar: