Como Construí o HashDocs: Arquitetura de uma Plataforma Blockchain
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:
- Processe arquivos de qualquer tamanho (até GBs)
- Gere fingerprints criptográficos únicos
- Registre na blockchain de forma confiável
- Seja rápido (< 5 segundos end-to-end)
- Não armazene arquivos (privacidade/LGPD)
- 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
- Input Validation: Frontend + Backend
- Rate Limiting: 10 uploads/minuto/IP
- File Streaming: Sem persistência
- Cryptographic Hashing: SHA-256 duplo
- 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:
- Performance: Rust para operações críticas
- Simplicidade: Web2.5 para melhor UX
- 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:
Artigos relacionados
Como Funciona a Certificação Blockchain: Guia Completo 2025
Descubra como a certificação blockchain garante a autenticidade de documentos de forma instantânea, segura e auditável. Guia completo com exemplos práticos.
HashDocs vs Cartório Tradicional: Comparação Completa de Custos e Tempo
Descubra as diferenças entre certificação blockchain e cartório tradicional. Análise detalhada de custos, tempo, segurança e validade jurídica.
LGPD e Blockchain: Guia Completo de Compliance e Privacidade
Como blockchain se encaixa na LGPD? Descubra como certificação blockchain garante compliance sem comprometer privacidade. Guia prático com checklist.
