Pular para o conteúdo
ZYNQORALABS
BC · Demonstração interna

Quorum IndexerIndexador EVM resistente a reorganizações

Arquitetura de referência para indexar eventos de contratos EVM em PostgreSQL com tratamento de reorganizações de cadeia, escrita idempotente e consenso entre provedores RPC.

Tecnologias
Go · PostgreSQL · EVM · Solidity ABI · Outbox
Demonstra
  • Tratamento de reorganizações
  • Escrita idempotente
  • Consenso entre provedores
  • Confirmação explícita

O desafio

  1. 01

    Blocos recentes podem ser substituídos. Um indexador ingênuo grava eventos que depois deixam de existir na cadeia canônica.

  2. 02

    Provedores RPC divergem, atrasam ou falham. Confiar em um só deixa o sistema cego sem perceber.

  3. 03

    Reprocessar um intervalo de blocos não pode duplicar saldos, transferências ou notificações.

Restrições

  • Várias redes EVM
  • Exatamente uma vez no efeito
  • Rastreabilidade até o bloco

Arquitetura

Do consenso entre RPCs à API: cada linha gravada carrega o hash do bloco que a originou.Fig. 01 · Quorum Indexer

Componentes

RPC providers
Três ou mais provedores independentes por rede.
Head quorum
Só avança quando a maioria concorda sobre o bloco mais recente.
Block fetcher
Busca blocos e logs em lotes, com retentativas por provedor.
Reorg detector
Compara o parentHash com os últimos N hashes armazenados.
ABI decoder
Transforma logs em eventos tipados por contrato.
PostgreSQL
Upsert por (chain_id, tx_hash, log_index); rollback por hash de bloco.
Query API
Consultas com o nível de confirmação explícito na resposta.
Webhooks
Notificações só após a profundidade de confirmação configurada.

Decisões de engenharia

D1Hash de bloco em toda linha

Escolha
Cada evento grava block_number e block_hash; uma reorganização remove as linhas pelos hashes órfãos.
Alternativa descartada
Gravar apenas o número do bloco.
Por quê
O número do bloco não muda em uma reorg, o hash sim. Sem ele, não há como saber quais linhas ficaram inválidas.

D2Chave natural idempotente

Escolha
Upsert por (chain_id, tx_hash, log_index).
Alternativa descartada
IDs gerados no momento da inserção.
Por quê
Reprocessar um intervalo vira uma operação segura, sem duplicatas, em vez de uma operação de risco.

D3Confirmação como dado, não como suposição

Escolha
A API expõe o estado de cada evento (pendente, seguro, finalizado) e os webhooks esperam a profundidade configurada.
Alternativa descartada
Tratar qualquer evento indexado como definitivo.
Por quê
Cada consumidor tem uma tolerância diferente. Um painel aceita dados recentes; uma liquidação não.

D4Quórum entre provedores

Escolha
O avanço da cabeça da cadeia exige concordância da maioria dos provedores.
Alternativa descartada
Um provedor principal com fallback.
Por quê
O fallback só age quando o provedor cai. O quórum também detecta o provedor que responde, mas está atrasado ou divergente.

Detalhes de implementação

O fetcher mantém em memória e no banco os hashes dos últimos 128 blocos processados. Ao receber um novo bloco, compara o parentHash com o hash armazenado da altura anterior; se divergirem, recua até encontrar o ancestral comum.

O rollback e a reaplicação acontecem na mesma transação, então consumidores nunca observam um estado intermediário. Webhooks são emitidos via outbox, só depois do commit e da profundidade de confirmação.

Cada rede roda como um worker independente. Uma rede lenta ou instável não atrasa as demais.

indexer/reorg.goTrecho representativo
// findCommonAncestor walks back from a new block until its parent matches what we stored.
func (ix *Indexer) findCommonAncestor(ctx context.Context, b *types.Header) (uint64, error) {
	for height := b.Number.Uint64() - 1; ; height-- {
		stored, ok := ix.recent.Hash(height)
		if !ok {
			return 0, ErrReorgDeeperThanWindow // alert: needs a manual resync
		}
		canonical, err := ix.quorum.HeaderByNumber(ctx, height)
		if err != nil {
			return 0, err
		}
		if canonical.Hash() == stored {
			return height, nil // rows above this height are orphaned
		}
	}
}

Resultados

Não aplicável. Por ser uma demonstração interna, não há métricas de produção verificadas a relatar, e não publicamos números estimados como se fossem resultados.

Tem um problema parecido?

Conte o contexto. Discutimos a arquitetura antes de qualquer proposta comercial.

Próximo estudoTessera RiskGateway de risco pré-negociação
01Quem é você

Usamos apenas para responder a esta solicitação.

02O projeto

O problema, o que já existe hoje e o que seria sucesso. Não inclua senhas ou dados pessoais de terceiros.

03Escopo

Usamos estes dados apenas para avaliar e responder à sua solicitação. Não vendemos nem compartilhamos com terceiros para marketing. Detalhes na política de privacidade.