Arquitetura (v2)¶
Hardening (issues #3–#17). A v2 recebeu: WAL de votos para crash-recovery seguro (#3), assinatura de registros anti-injeção (#4), observabilidade Prometheus + alertas (#5), segredos via arquivo + rotação de token (#6), coleta event-driven via Change Streams (#7), pipeline DevSecOps (#8), rate limiting/backpressure (#9), Postgres em CI + backup (#10), tracing OTel (#11), notificações webhook/SIEM (#12), prova de inclusão Merkle (#13), chart Helm HA (#14), spec TLA+ + fuzzing (#15), bootstrap de genesis (#16) e trilha de auditoria + dossiê LGPD (#17). Detalhes operacionais em operations.md, segurança/compliance em compliance/, verificação formal em ../specs/.
Visão geral¶
O Helix Blockchain é um ledger permissionado com consenso BFT que registra, de forma à prova de adulteração e acordada por múltiplos nós, a integridade dos dados dos brokers FIWARE Orion (Helix Sandbox NG). Ele não cifra dados — garante integridade, não confidencialidade.
Cada processo (helix-node) é um validador que:
- monitora o broker Orion principal e seus brokers federados,
- detecta adulteração comparando os valores federados com o broker principal,
- propõe/valida blocos via consenso BFT, e
- notifica adulterações somente após o bloco ser finalizado por consenso.
Camadas¶
collectors/ ── coleta Orion (MongoDB) + detecção de adulteração (lógica pura testável)
│
▼
network/ ── nó orquestrador + transporte P2P (HTTP) + servidor FastAPI
│
▼
consensus/ ── motor BFT (IBFT/PBFT): validadores, mensagens assinadas, quórum
│
▼
domain/ ── primitivas puras: cripto (Ed25519/SHA-256), Merkle, bloco, registros
│
▼
storage/ ── persistência (SQLAlchemy: SQLite/Postgres)
A regra de dependência aponta para baixo. domain/ não tem I/O e é 100% testável.
Modelo de consenso (IBFT/PBFT)¶
- Conjunto de N validadores conhecidos (permissionado). Tolera
f = (N−1)/3validadores bizantinos; o quórum éN − f. - O proposer de cada altura é escolhido por rodízio determinístico, então todos os nós honestos concordam sobre quem pode propor.
- Fluxo por altura
h(caminho feliz): - PRE-PREPARE — o proposer monta um bloco e o transmite.
- PREPARE — quem aceita a proposta transmite PREPARE; juntar
quórumPREPAREs prova que um quórum viu a mesma proposta. - COMMIT — ao atingir o quórum de PREPAREs, o validador trava o bloco e
transmite COMMIT com seu commit seal (assinatura sobre o hash do bloco).
Juntar
quórumCOMMITs finaliza o bloco. - Os commit seals coletados viram o certificado de finalidade persistido no
bloco — verificável de forma independente por
verify_finality().
Round change (liveness sob proposer faltante)¶
Se uma altura não fecha a tempo, cada nó chama on_timeout() e transmite uma
mensagem ROUND_CHANGE para a próxima rodada, escolhendo um novo proposer por
rodízio. Dois limiares governam a transição:
- f+1 ROUND_CHANGE para uma rodada maior → o nó "acelera" enviando o seu próprio (garante que nós atrasados avancem).
- quórum ROUND_CHANGE → o nó adota a nova rodada; seu proposer assume.
Segurança preservada por certificados. Cada ROUND_CHANGE carrega um prepared certificate — um quórum de mensagens PREPARE provando qual valor o remetente travou (se travou). O novo proposer re-propõe o valor travado de maior rodada entre o quórum de ROUND_CHANGE (ou um bloco novo, se nada estava travado), e anexa esse round-change certificate ao PRE_PREPARE para que todos verifiquem. Sem o prepared certificate, um nó bizantino poderia mentir sobre um valor travado e sequestrar a próxima proposta — por isso a prova é obrigatória.
Por que BFT em vez de PoW (como na v1)?¶
Num cenário permissionado de IoT, Proof-of-Work só desperdiça CPU sem agregar segurança (não há mineradores anônimos competindo). BFT dá finalidade imediata, custo baixo e tolerância a nós maliciosos — o que blockchains permissionadas reais usam (Hyperledger Besu IBFT, Quorum). A integridade do conteúdo é garantida pela árvore de Merkle no cabeçalho do bloco.
Detecção de adulteração¶
IntegrityChecker compara cada valor de atributo nos brokers federados com o
valor autoritativo do broker principal:
| Situação | Veredito |
|---|---|
| valor federado == principal | OK |
| valor federado != principal (alterado) | TAMPERED |
| entidade/atributo só existe no federado | TAMPERED |
RecordDeduper evita registrar repetidamente observações idênticas (equivale ao
monitora() legado).
Mempool e gossip¶
- Reconciliação de mempool (gossip de registros). Cada nó coleta do seu
próprio Orion. Ao observar registros novos, ele os compartilha com os peers
(
POST /mempool). Assim, uma adulteração detectada por um nó que não é o proposer da rodada ainda chega a quem vai propor, e entra na cadeia. Um conjuntomempool_seen(por id de registro) impede laços de gossip e re-inclusão de registros já commitados. - Gossip proativo de blocos. Ao finalizar um bloco, o nó o empurra aos
peers (
POST /block), além do pull sob demanda (fetch_block). Um nó que perdeu as rodadas de consenso recebe o bloco imediatamente; lacunas maiores ainda são preenchidas pelo pull-sync.
Segurança da camada P2P¶
- Autenticação por token de cluster. Os endpoints que alteram estado
(
/consensus,/mempool,/block,/admin/*) exigem um Bearer token compartilhado (HELIX_CLUSTER_TOKEN), comparado em tempo constante. Endpoints de leitura ficam abertos (blocos são auto-verificáveis pelo certificado de finalidade). Isso fecha a principal brecha: registros de/mempoolnão são assinados individualmente, então sem auth um peer poderia injetar relatos falsos de adulteração. Mensagens de consenso já são assinadas por validador. - TLS / mTLS. A camada P2P pode rodar sobre HTTPS (
HELIX_TLS__*), com mTLS opcional (cada validador apresenta e exige certificado de cliente, verificado contra a CA do cluster). O MongoDB do Orion também aceita CA própria (HELIX_ORION__TLS_CA_FILE). Gere certs de desenvolvimento compython -m helix_blockchain.tools.gen_certs.
Membership dinâmico de validadores¶
O conjunto de validadores pode mudar sem fork porque as mudanças são acordadas on-chain:
- Uma mudança (
ADD/REMOVEde uma chave pública) é conteúdo do bloco — coberta pela raiz de Merkle e finalizada por consenso. - O conjunto ativo numa altura
hé o conjunto genesis (configurado) com todas as mudanças dos blocos1..h-1aplicadas — uma mudança commitada no blocohvale a partir deh+1. Assim o blocohé sempre validado pelo conjunto anterior à sua própria mudança, e todos os nós derivam o mesmo conjunto/quórum a cada altura. - Um nó removido continua acompanhando a cadeia como follower passivo (sem motor de consenso) e pode voltar a votar se readicionado. A verificação de finalidade de cada bloco usa o conjunto ativo na altura daquele bloco.
- Mudanças de validador são propagadas por gossip (
/membership): qualquer proposer inclui as mudanças pendentes, então basta submeter a um validador. No-ops (adicionar existente / remover ausente) são descartados. - O bloco genesis embute o conjunto inicial (um
ADDpor validador), então o conjunto ativo é derivado puramente da cadeia — tamper-evident e uniforme.
Descoberta de peers¶
Com membership dinâmico, um validador adicionado depois não estaria no peers
estático dos demais. Cada nó mantém um registro dinâmico chave pública →
endereço, semeado da config e do próprio endereço anunciado
(HELIX_CONSENSUS__ADVERTISE), e o troca via /peers:
GET /peersdevolve os specs conhecidos (incluindo o próprio);POST /peersmescla specs recebidos (anúncio);- um loop periódico anuncia-se e puxa os registros dos peers, propagando o endereço de um recém-chegado pelo cluster. O transporte envia para os peers do registro (não da lista estática), então novos validadores são alcançados sem reinício. O registro é chaveado por chave pública: um re-anúncio com novo endereço atualiza no lugar.
Limitações conhecidas / trabalho futuro¶
- Construção do genesis ainda vem da config. O bloco genesis embute o conjunto inicial, mas cada nó o constrói localmente a partir da config (mesmo conjunto em todos). Um nó totalmente novo precisa do conjunto genesis correto na config (ou poderia sincronizar o bloco 0 de um peer — evolução futura).
- Descoberta exige ao menos um seed. Um nó novo precisa de pelo menos um peer configurado para se anunciar e puxar o restante do registro.
- Sem rotação de chaves de validador nem expiração de membership; mudanças
são manuais via
/admin/validator.