Adicione o Dalanga à tela de início

  1. 1. Toque no botão Compartilhar no Safari.
  2. 2. Escolha “Adicionar à Tela de Início”.
  3. 3. Toque em “Adicionar” para confirmar.
|

A Cadeia de Transparência Dalanga

Toda rifa na Dalanga é respaldada por um registro imutável e publicamente verificável.

Nosso Compromisso com a Transparência

A Dalanga foi construída sobre um princípio simples: toda rifa deve ser comprovadamente justa. Quando você compra um bilhete, merece saber que o sorteio foi honesto, que as regras não foram alteradas após o fato, e que o vencedor foi escolhido pela matemática — não pela decisão de alguém.

Para cumprir essa promessa, construímos a Cadeia de Transparência: um registro digital imutável que registra permanentemente cada evento significativo no ciclo de vida de uma rifa. Uma vez que um registro é gravado, ele não pode ser alterado ou excluído — nem por nós, nem por ninguém.

Você não precisa confiar em nós. Pode verificar por conta própria.

link

O que é a Cadeia de Transparência?

Pense na Cadeia de Transparência como um caderno digital onde cada página é conectada à anterior usando uma impressão digital matemática (chamada hash).

Cada página — chamamos de blocos — contém a descrição de algo que aconteceu: uma rifa foi criada, um bilhete foi comprado, um preço foi alterado ou um vencedor foi sorteado.

Cada bloco inclui o que aconteceu, quando aconteceu, quem fez e um vínculo matemático com o bloco anterior.

Como a impressão digital de cada bloco depende do bloco anterior, alterar qualquer registro passado quebraria a cadeia desse ponto em diante. Isso torna a adulteração imediatamente detectável.

Todos os eventos em toda a plataforma compartilham uma única cadeia sequencial. Percorrer a cadeia do início ao fim verifica o histórico completo da plataforma.

checklist

O que é Registrado

Cada ação significativa na plataforma cria um registro permanente.

Criação e Configuração de Rifas

  • check Rifa criada (título, limite de bilhetes, tipo de sorteio)
  • check Rifa publicada, pausada, despublicada ou cancelada
  • check Alterações de configuração (rastreadas campo por campo)
  • check Atualizações de parâmetros de equidade (ex.: expiração de reserva)

Bilhetes

  • check Bilhete comprado (online ou papel)
  • check Pagamento de bilhete confirmado
  • check Bilhete cancelado

Preços e Mídia

  • check Preço adicionado, alterado ou removido (com valores antigos e novos)
  • check Imagens de prêmios adicionadas ou removidas

O Sorteio

  • check Compromisso do sorteio publicado (parâmetros bloqueados antes do sorteio)
  • check Sorteio revelado (semente tornada pública, derivação do vencedor mostrada)
  • check Bilhete vencedor selecionado

Lojas e Criadores

  • check Loja criada, atualizada, mudanças de status
  • check Perfil de criador criado, atualizado, mudanças de verificação
  • check Alterações de logotipo da loja

Financeiro e Moderação

  • check Pagamentos a criadores criados e mudanças de status
  • check Denúncias de lojas registradas e mudanças de status
  • check Transações de carteira

Ciclo de Vida do Usuário

  • check Registro de conta e verificação de e-mail
  • check Atualizações de perfil e solicitações de exclusão de conta

Informações pessoais são armazenadas separadamente da cadeia permanente e podem ser removidas mediante solicitação conforme a lei de privacidade (LGPD).

casino

Como o Sorteio Funciona

Todo sorteio na Dalanga usa um processo de compromisso-revelação que torna matematicamente impossível que qualquer pessoa — incluindo nós — influencie o resultado.

1

Passo 1: Compromisso

  • arrow_right Gera uma semente secreta aleatória (64 caracteres aleatórios)
  • arrow_right Captura um instantâneo de todos os bilhetes elegíveis (pagos), em ordem
  • arrow_right Combina a semente com a lista de bilhetes e produz um hash de compromisso
  • arrow_right Publica o hash de compromisso na Cadeia de Transparência
  • arrow_right Tranca a semente, criptografada, até o sorteio

Neste ponto, o resultado já está determinado — mas ninguém pode vê-lo ainda, porque a semente está criptografada.

2

Passo 2: Revelação

  • arrow_right Descriptografa e publica a semente
  • arrow_right Executa a fórmula de seleção do vencedor usando hash SHA-256, aritmética modular e a lista ordenada de bilhetes
  • arrow_right Registra o cálculo completo na Cadeia de Transparência

Por que Isso Importa

Como o hash de compromisso foi publicado antes da semente ser revelada, qualquer pessoa pode verificar que a semente não foi alterada, o vencedor foi derivado exatamente como descrito, e nenhum humano fez a escolha — apenas a matemática.

verified_user

Como Verificar por Conta Própria

visibility

Fácil: Navegue pelo Explorador de Cadeia

Cada página de rifa inclui um link para seu Explorador de Cadeia — um navegador visual onde você pode ver cada evento registrado, quando aconteceu, e as provas matemáticas conectando cada bloco. Nenhum conhecimento técnico necessário.

A plataforma também oferece um Explorador de Cadeia do Sistema para navegar pela cadeia global completa.

download

Médio: Baixe a Exportação da Cadeia

Na página de cadeia de qualquer rifa, você pode baixar a cadeia completa como arquivo JSON. Este arquivo contém cada bloco, cada hash e cada registro de âncora. Você pode abri-lo em qualquer editor de texto ou visualizador JSON para inspecionar os dados brutos.

terminal

Avançado: Execute a Ferramenta de Verificação

Fornecemos scripts de verificação de código aberto em PHP, Python, Bash e Node.js que verificam toda a cadeia offline. Eles verificam cada hash, cada vínculo, re-derivam vencedores de sorteios e verificam hashes de compromisso — nenhuma conta necessária.

shield

Privacidade e Direitos de Dados

Como Separamos os Dados

A cadeia em si contém apenas resumos não pessoais: tipos de eventos, mudanças de status, números de bilhetes, timestamps e provas matemáticas. Informações pessoais são armazenadas em uma camada separada e removível.

Um compromisso matemático (hash) em cada bloco da cadeia prova que os dados completos existiam no momento do registro — sem expor detalhes pessoais na cadeia permanente.

Seu Direito à Exclusão

Pela LGPD, você pode solicitar a exclusão dos seus dados pessoais. Quando isso acontece, suas informações pessoais são removidas da camada de dados separada, os blocos permanentes da cadeia permanecem inalterados, registros limpos são marcados de forma transparente, e o compromisso matemático ainda prova quais eram os dados originais.

Este design nos permite honrar seus direitos de privacidade mantendo a integridade da cadeia para todos.

Explorar a Cadeia

Toda rifa na Dalanga é respaldada por um registro imutável e publicamente verificável.

code

Apêndice Técnico

sequence   INTEGER   Auto-incrementing block number
event_type VARCHAR   Category of recorded event
event_data JSON      Structured event payload
actor      VARCHAR   Who triggered the event
hash_input TEXT      Canonical input fed to SHA-256
hash       CHAR(64)  SHA-256 digest of hash_input
prev_hash  CHAR(64)  Hash of the preceding block (null for genesis)
payload_hash CHAR(64) SHA-256 of the full event payload
created_at TIMESTAMP When the block was recorded

SHA-256 com codificação JSON canônica (barras e unicode não escapados)

hash_input = sequence|event_type|json(event_data)|actor|previous_hash
hash       = sha256(hash_input)

Cadeia de blocos global única — todos os eventos em todos os domínios compartilham uma cadeia sequencial. Sem particionamento por rifa.

draw_hash    = sha256(seed + sorted_ticket_numbers)
winner_index = hex_to_int(draw_hash[0:12]) mod ticket_count
winner       = sorted_tickets[winner_index]
raffle.* — Raffle lifecycle
ticket.* — Ticket events
price.* — Price changes
draw.* — Draw phases
store.* — Store events
creator.* — Creator events
media.* — Media changes
user.* — User lifecycle
payout.* — Creator payouts
wallet.* — Wallet events
report.* — Store reports

Fornecemos scripts de verificação de código aberto em vários idiomas. Cada script é independente e sem dependências externas (Bash requer jq, sha256sum e bc). Baixe ou copie qualquer script abaixo e execute contra um arquivo de exportação da cadeia para verificar independentemente cada bloco.

Exemplo:

# Download the chain and verify:
curl -s https://dalanga.com/api/system-chain/export -o chain.json
php verify-chain.php chain.json
#!/usr/bin/env php
<?php

/**
 * Dalanga Transparency Chain Verification Tool
 *
 * A standalone, zero-dependency PHP script that verifies the integrity of a
 * downloaded Dalanga system chain export file.
 *
 * Requirements: PHP 8.0+ with JSON and hash extensions (standard in all PHP installs).
 * No Composer, no autoloader, no framework dependencies.
 *
 * Usage:
 *   php verify-chain.php <path-to-export.json>
 *
 * Examples:
 *   php verify-chain.php system-chain-export.json
 *   php verify-chain.php /tmp/chain-export.json
 *
 * What it verifies:
 *   1. Consecutive sequence numbers starting from 0
 *   2. Hash linking: each block's previous_hash matches the preceding block's hash
 *   3. Hash recomputation: re-hashes each block's hash_input and compares to stored hash
 *   4. Genesis block validation: sequence 0 must have previous_hash = null
 *   5. Draw fairness: for draw.revealed events, re-derives the winner using the
 *      algorithm_version from event_data and confirms the recorded winner matches
 *
 * Exit codes:
 *   0 = Chain is valid (all checks passed)
 *   1 = Chain is invalid (one or more checks failed)
 *   2 = Usage error (missing file, invalid JSON, etc.)
 */

// ANSI color codes
define('GREEN', "\033[32m");
define('RED', "\033[31m");
define('RESET', "\033[0m");
define('BOLD', "\033[1m");

function success(string $message): void
{
    echo GREEN.'✓'.RESET.' '.$message.PHP_EOL;
}

function failure(string $message): void
{
    echo RED.'✗'.RESET.' '.$message.PHP_EOL;
}

function canonical_json_encode(mixed $data): string
{
    return json_encode(sort_keys_recursive($data), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}

function sort_keys_recursive(mixed $data): mixed
{
    if (! is_array($data)) {
        return $data;
    }

    if (array_is_list($data)) {
        return array_map('sort_keys_recursive', $data);
    }

    ksort($data);

    return array_map('sort_keys_recursive', $data);
}

// ─── Input Validation ────────────────────────────────────────────────

if ($argc < 2) {
    echo 'Dalanga Transparency Chain Verification Tool'.PHP_EOL;
    echo PHP_EOL;
    echo 'Usage: php '.basename($argv[0]).' <path-to-export.json>'.PHP_EOL;
    echo PHP_EOL;
    echo 'Verifies the cryptographic integrity of a chain export file.'.PHP_EOL;
    echo 'For draw events, re-derives the winner to confirm fairness.'.PHP_EOL;
    exit(2);
}

$path = $argv[1];

if (! file_exists($path)) {
    failure("File not found: {$path}");
    exit(2);
}

$content = file_get_contents($path);
$data = json_decode($content, true);

if ($data === null) {
    failure('Invalid JSON: '.json_last_error_msg());
    exit(2);
}

if (! isset($data['blocks']) || ! is_array($data['blocks'])) {
    failure('Invalid export format: missing "blocks" array');
    exit(2);
}

// ─── Chain Verification ──────────────────────────────────────────────

$blocks = $data['blocks'];
$blockCount = count($blocks);
$errors = 0;

echo BOLD.'Dalanga Transparency Chain Verifier'.RESET.PHP_EOL;

if (isset($data['chain'])) {
    echo 'Chain: '.$data['chain'].PHP_EOL;
}

if (isset($data['exported_at'])) {
    echo 'Exported: '.$data['exported_at'].PHP_EOL;
}

echo 'Blocks: '.$blockCount.PHP_EOL;
echo PHP_EOL;

if ($blockCount === 0) {
    success('Chain is empty (0 blocks)');
    exit(0);
}

// Chain integrity checks
for ($i = 0; $i < $blockCount; $i++) {
    $block = $blocks[$i];

    // Check consecutive sequences
    if ($block['sequence'] !== $i) {
        failure("Block {$i}: expected sequence {$i}, got {$block['sequence']}");
        $errors++;

        continue;
    }

    // Genesis block validation
    if ($i === 0 && $block['previous_hash'] !== null) {
        failure('Block 0: genesis block must have previous_hash = null');
        $errors++;
    }

    // Hash linking
    if ($i > 0 && $block['previous_hash'] !== $blocks[$i - 1]['hash']) {
        failure("Block {$i}: previous_hash does not match preceding block's hash");
        $errors++;
    }

    // Hash recomputation
    $recomputedHash = hash('sha256', $block['hash_input']);

    if ($block['hash'] !== $recomputedHash) {
        failure("Block {$i}: hash does not match recomputed hash from hash_input");
        $errors++;
    } else {
        $eventType = $block['event_type'] ?? 'unknown';
        success("Block {$i}: hash valid ({$eventType})");
    }
}

// ─── Payload Hash Verification ──────────────────────────────────────

$hasPayloadHashes = false;

foreach ($blocks as $block) {
    if (isset($block['payload_hash'])) {
        $hasPayloadHashes = true;

        break;
    }
}

if ($hasPayloadHashes) {
    echo PHP_EOL;
    echo BOLD.'Payload Hash Verification'.RESET.PHP_EOL;
    $payloadChecked = 0;
    $payloadSkipped = 0;

    foreach ($blocks as $block) {
        if (! isset($block['payload_hash'])) {
            continue;
        }

        if (! isset($block['payload'])) {
            $payloadSkipped++;

            continue;
        }

        $payloadChecked++;
        $recomputedPayloadHash = hash('sha256', canonical_json_encode($block['payload']));

        if ($block['payload_hash'] !== $recomputedPayloadHash) {
            failure("Block {$block['sequence']}: payload_hash does not match recomputed hash from payload");
            $errors++;
        } else {
            success("Block {$block['sequence']}: payload hash valid ({$block['event_type']})");
        }
    }

    if ($payloadSkipped > 0) {
        echo "(Skipped {$payloadSkipped} block(s) without payload data — blocks-only export)".PHP_EOL;
    }

    echo "Payload hashes checked: {$payloadChecked}, skipped: {$payloadSkipped}".PHP_EOL;
}

// ─── Anchor Event Verification ───────────────────────────────────────

$anchorConfiguredCount = 0;
$anchoredBlocks = [];

foreach ($blocks as $block) {
    $eventType = $block['event_type'] ?? null;

    if ($eventType === 'chain.anchor_configured') {
        $anchorConfiguredCount++;
        $eventData = $block['event_data'] ?? [];

        if (! isset($eventData['anchor_service'])) {
            failure("Block {$block['sequence']}: chain.anchor_configured missing anchor_service");
            $errors++;
        } else {
            success("Block {$block['sequence']}: anchor configured ({$eventData['anchor_service']})");
        }

        if ($anchorConfiguredCount > 1) {
            failure("Block {$block['sequence']}: duplicate chain.anchor_configured (expected at most 1)");
            $errors++;
        }
    }

    if ($eventType === 'chain.anchored') {
        $eventData = $block['event_data'] ?? [];

        if (! isset($eventData['anchor_service'])) {
            failure("Block {$block['sequence']}: chain.anchored missing anchor_service");
            $errors++;
        }

        if (! isset($eventData['anchor_reference'])) {
            failure("Block {$block['sequence']}: chain.anchored missing anchor_reference");
            $errors++;
        }

        if (! isset($eventData['chain_state_hash'])) {
            failure("Block {$block['sequence']}: chain.anchored missing chain_state_hash");
            $errors++;
        }

        if (! isset($eventData['block_count'])) {
            failure("Block {$block['sequence']}: chain.anchored missing block_count");
            $errors++;
        }

        if (! isset($eventData['block_sequence'])) {
            failure("Block {$block['sequence']}: chain.anchored missing block_sequence");
            $errors++;
        } else {
            // anchor's block_sequence must reference a block that exists before this anchor block
            if ($eventData['block_sequence'] >= $block['sequence']) {
                failure("Block {$block['sequence']}: chain.anchored references block_sequence {$eventData['block_sequence']} which is not before this block");
                $errors++;
            } else {
                success("Block {$block['sequence']}: anchor record valid ({$eventData['anchor_service']} @ seq {$eventData['block_sequence']})");
            }
        }

        $anchoredBlocks[] = $block;
    }
}

if ($anchoredBlocks !== []) {
    echo PHP_EOL;
    echo BOLD.'Anchor History'.RESET.PHP_EOL;
    echo 'Anchor configuration events: '.$anchorConfiguredCount.PHP_EOL;
    echo 'Anchor records on-chain: '.count($anchoredBlocks).PHP_EOL;

    foreach ($anchoredBlocks as $ab) {
        $ed = $ab['event_data'] ?? [];
        $service = $ed['anchor_service'] ?? '?';
        $ref = $ed['anchor_reference'] ?? '';
        $seq = $ed['block_sequence'] ?? '?';
        echo "  [{$service}] seq {$seq} → {$ref}".PHP_EOL;
    }
}

// ─── Draw Event Verification ─────────────────────────────────────────

$committedBlocks = [];

foreach ($blocks as $block) {
    if (($block['event_type'] ?? null) === 'draw.committed') {
        $committedBlocks[] = $block;
    }
}

foreach ($blocks as $block) {
    if (($block['event_type'] ?? null) !== 'draw.revealed') {
        continue;
    }

    $eventData = $block['event_data'] ?? [];
    $algorithmVersion = $eventData['algorithm_version'] ?? null;

    if ($algorithmVersion === null) {
        failure("Block {$block['sequence']}: draw.revealed missing algorithm_version");
        $errors++;

        continue;
    }

    if ($algorithmVersion !== 'sha256-modulo-v1') {
        failure("Block {$block['sequence']}: unknown algorithm version '{$algorithmVersion}'");
        $errors++;

        continue;
    }

    // Find matching draw.committed block
    $committed = null;

    foreach ($committedBlocks as $cb) {
        $cbData = $cb['event_data'] ?? [];
        if (isset($cbData['eligible_tickets_snapshot'])) {
            $committed = $cb;
        }
    }

    if ($committed === null) {
        failure("Block {$block['sequence']}: draw.revealed but no matching draw.committed found");
        $errors++;

        continue;
    }

    $committedData = $committed['event_data'];
    $seed = $eventData['seed'];
    $eligibleTickets = $committedData['eligible_tickets_snapshot'];
    $totalEligible = count($eligibleTickets);

    // Re-derive winner using sha256-modulo-v1
    $winnerIndex = hexdec(substr(hash('sha256', $seed), 0, 12)) % $totalEligible;
    $winnerTicketNumber = $eligibleTickets[$winnerIndex];

    if ($winnerIndex !== $eventData['winner_index']) {
        failure("Block {$block['sequence']}: draw winner_index mismatch (expected {$winnerIndex}, got {$eventData['winner_index']})");
        $errors++;
    } elseif ($winnerTicketNumber !== $eventData['winner_ticket_number']) {
        failure("Block {$block['sequence']}: draw winner_ticket_number mismatch (expected {$winnerTicketNumber}, got {$eventData['winner_ticket_number']})");
        $errors++;
    } else {
        success("Block {$block['sequence']}: draw winner independently verified (sha256-modulo-v1)");
    }

    // Verify commitment hash
    $commitmentHash = $committedData['commitment_hash'] ?? null;

    if ($commitmentHash !== null) {
        $recomputedCommitment = hash('sha256', $seed.json_encode($eligibleTickets));

        if ($commitmentHash !== $recomputedCommitment) {
            failure("Block {$committed['sequence']}: commitment hash mismatch");
            $errors++;
        } else {
            success("Block {$committed['sequence']}: commitment hash verified");
        }
    }
}

// ─── Summary ─────────────────────────────────────────────────────────

echo PHP_EOL;

if ($errors === 0) {
    echo GREEN."Chain valid: {$blockCount} blocks verified, 0 errors".RESET.PHP_EOL;
    exit(0);
}

echo RED."Chain INVALID: {$blockCount} blocks verified, {$errors} error(s)".RESET.PHP_EOL;
exit(1);
php verify-chain.php export.json download Baixar
#!/usr/bin/env python3
"""
Dalanga Transparency Chain Verification Tool

A standalone, zero-dependency Python script that verifies the integrity of a
downloaded Dalanga system chain export file.

Requirements: Python 3.6+ (standard library only).

Usage:
  python3 verify-chain.py <path-to-export.json>

Examples:
  python3 verify-chain.py system-chain-export.json
  python3 verify-chain.py /tmp/chain-export.json

What it verifies:
  1. Consecutive sequence numbers starting from 0
  2. Hash linking: each block's previous_hash matches the preceding block's hash
  3. Hash recomputation: re-hashes each block's hash_input and compares to stored hash
  4. Genesis block validation: sequence 0 must have previous_hash = null
  5. Payload hash verification: re-hashes payload and compares to stored payload_hash
  6. Draw fairness: for draw.revealed events, re-derives the winner using the
     algorithm_version from event_data and confirms the recorded winner matches

Exit codes:
  0 = Chain is valid (all checks passed)
  1 = Chain is invalid (one or more checks failed)
  2 = Usage error (missing file, invalid JSON, etc.)
"""

import hashlib
import json
import sys

# ANSI color codes
GREEN = "\033[32m"
RED = "\033[31m"
RESET = "\033[0m"
BOLD = "\033[1m"


def success(message: str) -> None:
    print(f"{GREEN}\u2713{RESET} {message}")


def failure(message: str) -> None:
    print(f"{RED}\u2717{RESET} {message}")


# --- Input Validation -------------------------------------------------------

if len(sys.argv) < 2:
    print("Dalanga Transparency Chain Verification Tool")
    print()
    print(f"Usage: python3 {sys.argv[0]} <path-to-export.json>")
    print()
    print("Verifies the cryptographic integrity of a chain export file.")
    print("For draw events, re-derives the winner to confirm fairness.")
    sys.exit(2)

path = sys.argv[1]

try:
    with open(path, "r", encoding="utf-8") as f:
        content = f.read()
except FileNotFoundError:
    failure(f"File not found: {path}")
    sys.exit(2)
except OSError as e:
    failure(f"Cannot read file: {e}")
    sys.exit(2)

try:
    data = json.loads(content)
except json.JSONDecodeError as e:
    failure(f"Invalid JSON: {e}")
    sys.exit(2)

if not isinstance(data.get("blocks"), list):
    failure('Invalid export format: missing "blocks" array')
    sys.exit(2)

# --- Chain Verification ------------------------------------------------------

blocks = data["blocks"]
block_count = len(blocks)
errors = 0

print(f"{BOLD}Dalanga Transparency Chain Verifier{RESET}")

if "chain" in data:
    print(f"Chain: {data['chain']}")

if "exported_at" in data:
    print(f"Exported: {data['exported_at']}")

print(f"Blocks: {block_count}")
print()

if block_count == 0:
    success("Chain is empty (0 blocks)")
    sys.exit(0)

# Chain integrity checks
for i in range(block_count):
    block = blocks[i]

    # Check consecutive sequences
    if block["sequence"] != i:
        failure(f"Block {i}: expected sequence {i}, got {block['sequence']}")
        errors += 1
        continue

    # Genesis block validation
    if i == 0 and block["previous_hash"] is not None:
        failure("Block 0: genesis block must have previous_hash = null")
        errors += 1

    # Hash linking
    if i > 0 and block["previous_hash"] != blocks[i - 1]["hash"]:
        failure(f"Block {i}: previous_hash does not match preceding block's hash")
        errors += 1

    # Hash recomputation
    recomputed_hash = hashlib.sha256(block["hash_input"].encode("utf-8")).hexdigest()

    if block["hash"] != recomputed_hash:
        failure(f"Block {i}: hash does not match recomputed hash from hash_input")
        errors += 1
    else:
        event_type = block.get("event_type", "unknown")
        success(f"Block {i}: hash valid ({event_type})")

# --- Payload Hash Verification -----------------------------------------------

has_payload_hashes = any("payload_hash" in b for b in blocks)

if has_payload_hashes:
    print()
    print(f"{BOLD}Payload Hash Verification{RESET}")
    payload_checked = 0
    payload_skipped = 0

    for block in blocks:
        if "payload_hash" not in block:
            continue

        if "payload" not in block:
            payload_skipped += 1
            continue

        payload_checked += 1
        payload_json = json.dumps(block["payload"], ensure_ascii=False, separators=(",", ":"), sort_keys=True)
        recomputed_payload_hash = hashlib.sha256(payload_json.encode("utf-8")).hexdigest()

        if block["payload_hash"] != recomputed_payload_hash:
            failure(f"Block {block['sequence']}: payload_hash does not match recomputed hash from payload")
            errors += 1
        else:
            success(f"Block {block['sequence']}: payload hash valid ({block['event_type']})")

    if payload_skipped > 0:
        print(f"(Skipped {payload_skipped} block(s) without payload data \u2014 blocks-only export)")

    print(f"Payload hashes checked: {payload_checked}, skipped: {payload_skipped}")

# --- Draw Event Verification -------------------------------------------------

committed_blocks = [b for b in blocks if b.get("event_type") == "draw.committed"]

for block in blocks:
    if block.get("event_type") != "draw.revealed":
        continue

    event_data = block.get("event_data", {})
    algorithm_version = event_data.get("algorithm_version")

    if algorithm_version is None:
        failure(f"Block {block['sequence']}: draw.revealed missing algorithm_version")
        errors += 1
        continue

    if algorithm_version != "sha256-modulo-v1":
        failure(f"Block {block['sequence']}: unknown algorithm version '{algorithm_version}'")
        errors += 1
        continue

    # Find matching draw.committed block
    committed = None
    for cb in committed_blocks:
        cb_data = cb.get("event_data", {})
        if "eligible_tickets_snapshot" in cb_data:
            committed = cb

    if committed is None:
        failure(f"Block {block['sequence']}: draw.revealed but no matching draw.committed found")
        errors += 1
        continue

    committed_data = committed["event_data"]
    seed = event_data["seed"]
    eligible_tickets = committed_data["eligible_tickets_snapshot"]
    total_eligible = len(eligible_tickets)

    # Re-derive winner using sha256-modulo-v1
    winner_index = int(hashlib.sha256(seed.encode("utf-8")).hexdigest()[:12], 16) % total_eligible
    winner_ticket_number = eligible_tickets[winner_index]

    if winner_index != event_data["winner_index"]:
        failure(f"Block {block['sequence']}: draw winner_index mismatch (expected {winner_index}, got {event_data['winner_index']})")
        errors += 1
    elif winner_ticket_number != event_data["winner_ticket_number"]:
        failure(f"Block {block['sequence']}: draw winner_ticket_number mismatch (expected {winner_ticket_number}, got {event_data['winner_ticket_number']})")
        errors += 1
    else:
        success(f"Block {block['sequence']}: draw winner independently verified (sha256-modulo-v1)")

    # Verify commitment hash
    commitment_hash = committed_data.get("commitment_hash")

    if commitment_hash is not None:
        recomputed_commitment = hashlib.sha256(
            (seed + json.dumps(eligible_tickets, separators=(",", ":"))).encode("utf-8")
        ).hexdigest()

        if commitment_hash != recomputed_commitment:
            failure(f"Block {committed['sequence']}: commitment hash mismatch")
            errors += 1
        else:
            success(f"Block {committed['sequence']}: commitment hash verified")

# --- Summary -----------------------------------------------------------------

print()

if errors == 0:
    print(f"{GREEN}Chain valid: {block_count} blocks verified, 0 errors{RESET}")
    sys.exit(0)

print(f"{RED}Chain INVALID: {block_count} blocks verified, {errors} error(s){RESET}")
sys.exit(1)
python3 verify-chain.py export.json download Baixar
#!/usr/bin/env bash
set -euo pipefail

# Dalanga Transparency Chain Verification Tool
#
# A standalone Bash script that verifies the integrity of a downloaded
# Dalanga system chain export file.
#
# Requirements: jq, sha256sum (or shasum), bc
#
# Usage:
#   bash verify-chain.sh <path-to-export.json>
#
# Examples:
#   bash verify-chain.sh system-chain-export.json
#   bash verify-chain.sh /tmp/chain-export.json
#
# What it verifies:
#   1. Consecutive sequence numbers starting from 0
#   2. Hash linking: each block's previous_hash matches the preceding block's hash
#   3. Hash recomputation: re-hashes each block's hash_input and compares to stored hash
#   4. Genesis block validation: sequence 0 must have previous_hash = null
#   5. Payload hash verification: re-hashes payload and compares to stored payload_hash
#   6. Draw fairness: for draw.revealed events, re-derives the winner using the
#      algorithm_version from event_data and confirms the recorded winner matches
#
# Exit codes:
#   0 = Chain is valid (all checks passed)
#   1 = Chain is invalid (one or more checks failed)
#   2 = Usage error (missing file, invalid JSON, etc.)

# ANSI color codes
GREEN="\033[32m"
RED="\033[31m"
RESET="\033[0m"
BOLD="\033[1m"

success() { echo -e "${GREEN}✓${RESET} $1"; }
failure() { echo -e "${RED}✗${RESET} $1"; }

# --- Dependency Checks -------------------------------------------------------

check_deps() {
    local missing=()

    if ! command -v jq &>/dev/null; then
        missing+=("jq")
    fi
    if ! command -v sha256sum &>/dev/null && ! command -v shasum &>/dev/null; then
        missing+=("sha256sum or shasum")
    fi
    if ! command -v bc &>/dev/null; then
        missing+=("bc")
    fi

    if [[ ${#missing[@]} -gt 0 ]]; then
        echo "Missing required dependencies: ${missing[*]}"
        echo ""
        echo "Install instructions:"
        echo "  macOS (Homebrew):  brew install ${missing[*]}"
        echo "  Ubuntu/Debian:     sudo apt-get install ${missing[*]}"
        echo "  RHEL/Fedora:       sudo yum install ${missing[*]}"
        exit 2
    fi
}

check_deps

# SHA-256 wrapper (Linux vs macOS)
sha256_hash() {
    if command -v sha256sum &>/dev/null; then
        printf '%s' "$1" | sha256sum | cut -d' ' -f1
    else
        printf '%s' "$1" | shasum -a 256 | cut -d' ' -f1
    fi
}

# --- Input Validation --------------------------------------------------------

if [[ $# -lt 1 ]]; then
    echo "Dalanga Transparency Chain Verification Tool"
    echo ""
    echo "Usage: bash $(basename "$0") <path-to-export.json>"
    echo ""
    echo "Verifies the cryptographic integrity of a chain export file."
    echo "For draw events, re-derives the winner to confirm fairness."
    exit 2
fi

FILE="$1"

if [[ ! -f "$FILE" ]]; then
    failure "File not found: $FILE"
    exit 2
fi

if ! jq empty "$FILE" 2>/dev/null; then
    failure "Invalid JSON in file: $FILE"
    exit 2
fi

if ! jq -e '.blocks | type == "array"' "$FILE" >/dev/null 2>&1; then
    failure 'Invalid export format: missing "blocks" array'
    exit 2
fi

# --- Chain Verification ------------------------------------------------------

BLOCK_COUNT=$(jq '.blocks | length' "$FILE")
ERRORS=0

echo -e "${BOLD}Dalanga Transparency Chain Verifier${RESET}"

CHAIN=$(jq -r '.chain // empty' "$FILE")
[[ -n "$CHAIN" ]] && echo "Chain: $CHAIN"

EXPORTED_AT=$(jq -r '.exported_at // empty' "$FILE")
[[ -n "$EXPORTED_AT" ]] && echo "Exported: $EXPORTED_AT"

echo "Blocks: $BLOCK_COUNT"
echo ""

if [[ "$BLOCK_COUNT" -eq 0 ]]; then
    success "Chain is empty (0 blocks)"
    exit 0
fi

# Chain integrity checks
PREV_HASH=""
for (( i=0; i<BLOCK_COUNT; i++ )); do
    BLOCK=$(jq -c ".blocks[$i]" "$FILE")

    SEQ=$(echo "$BLOCK" | jq -r '.sequence')
    BLOCK_PREV_HASH=$(echo "$BLOCK" | jq -r '.previous_hash // "null"')
    BLOCK_HASH=$(echo "$BLOCK" | jq -r '.hash')
    HASH_INPUT=$(echo "$BLOCK" | jq -r '.hash_input')
    EVENT_TYPE=$(echo "$BLOCK" | jq -r '.event_type // "unknown"')

    # Check consecutive sequences
    if [[ "$SEQ" != "$i" ]]; then
        failure "Block $i: expected sequence $i, got $SEQ"
        ERRORS=$((ERRORS + 1))
        continue
    fi

    # Genesis block validation
    if [[ "$i" -eq 0 && "$BLOCK_PREV_HASH" != "null" ]]; then
        failure "Block 0: genesis block must have previous_hash = null"
        ERRORS=$((ERRORS + 1))
    fi

    # Hash linking
    if [[ "$i" -gt 0 && "$BLOCK_PREV_HASH" != "$PREV_HASH" ]]; then
        failure "Block $i: previous_hash does not match preceding block's hash"
        ERRORS=$((ERRORS + 1))
    fi

    # Hash recomputation
    RECOMPUTED_HASH=$(sha256_hash "$HASH_INPUT")

    if [[ "$BLOCK_HASH" != "$RECOMPUTED_HASH" ]]; then
        failure "Block $i: hash does not match recomputed hash from hash_input"
        ERRORS=$((ERRORS + 1))
    else
        success "Block $i: hash valid ($EVENT_TYPE)"
    fi

    PREV_HASH="$BLOCK_HASH"
done

# --- Payload Hash Verification -----------------------------------------------

HAS_PAYLOAD_HASHES=$(jq '[.blocks[] | has("payload_hash")] | any' "$FILE")

if [[ "$HAS_PAYLOAD_HASHES" == "true" ]]; then
    echo ""
    echo -e "${BOLD}Payload Hash Verification${RESET}"
    PAYLOAD_CHECKED=0
    PAYLOAD_SKIPPED=0

    for (( i=0; i<BLOCK_COUNT; i++ )); do
        BLOCK=$(jq -c ".blocks[$i]" "$FILE")
        HAS_PH=$(echo "$BLOCK" | jq 'has("payload_hash")')
        [[ "$HAS_PH" != "true" ]] && continue

        HAS_PAYLOAD=$(echo "$BLOCK" | jq 'has("payload")')
        if [[ "$HAS_PAYLOAD" != "true" ]]; then
            PAYLOAD_SKIPPED=$((PAYLOAD_SKIPPED + 1))
            continue
        fi

        PAYLOAD_CHECKED=$((PAYLOAD_CHECKED + 1))
        PAYLOAD_HASH=$(echo "$BLOCK" | jq -r '.payload_hash')
        PAYLOAD_JSON=$(echo "$BLOCK" | jq -cS '.payload')
        RECOMPUTED_PH=$(sha256_hash "$PAYLOAD_JSON")
        BLOCK_SEQ=$(echo "$BLOCK" | jq -r '.sequence')
        BLOCK_ET=$(echo "$BLOCK" | jq -r '.event_type')

        if [[ "$PAYLOAD_HASH" != "$RECOMPUTED_PH" ]]; then
            failure "Block $BLOCK_SEQ: payload_hash does not match recomputed hash from payload"
            ERRORS=$((ERRORS + 1))
        else
            success "Block $BLOCK_SEQ: payload hash valid ($BLOCK_ET)"
        fi
    done

    if [[ "$PAYLOAD_SKIPPED" -gt 0 ]]; then
        echo "(Skipped $PAYLOAD_SKIPPED block(s) without payload data — blocks-only export)"
    fi

    echo "Payload hashes checked: $PAYLOAD_CHECKED, skipped: $PAYLOAD_SKIPPED"
fi

# --- Draw Event Verification -------------------------------------------------

# Collect committed blocks
COMMITTED_BLOCKS=$(jq -c '[.blocks[] | select(.event_type == "draw.committed")]' "$FILE")

for (( i=0; i<BLOCK_COUNT; i++ )); do
    BLOCK=$(jq -c ".blocks[$i]" "$FILE")
    EVENT_TYPE=$(echo "$BLOCK" | jq -r '.event_type // empty')
    [[ "$EVENT_TYPE" != "draw.revealed" ]] && continue

    BLOCK_SEQ=$(echo "$BLOCK" | jq -r '.sequence')
    ALG_VERSION=$(echo "$BLOCK" | jq -r '.event_data.algorithm_version // empty')

    if [[ -z "$ALG_VERSION" ]]; then
        failure "Block $BLOCK_SEQ: draw.revealed missing algorithm_version"
        ERRORS=$((ERRORS + 1))
        continue
    fi

    if [[ "$ALG_VERSION" != "sha256-modulo-v1" ]]; then
        failure "Block $BLOCK_SEQ: unknown algorithm version '$ALG_VERSION'"
        ERRORS=$((ERRORS + 1))
        continue
    fi

    # Find matching draw.committed block with eligible_tickets_snapshot
    COMMITTED=$(echo "$COMMITTED_BLOCKS" | jq -c '[.[] | select(.event_data.eligible_tickets_snapshot != null)] | last')

    if [[ "$COMMITTED" == "null" || -z "$COMMITTED" ]]; then
        failure "Block $BLOCK_SEQ: draw.revealed but no matching draw.committed found"
        ERRORS=$((ERRORS + 1))
        continue
    fi

    SEED=$(echo "$BLOCK" | jq -r '.event_data.seed')
    ELIGIBLE_TICKETS=$(echo "$COMMITTED" | jq -c '.event_data.eligible_tickets_snapshot')
    TOTAL_ELIGIBLE=$(echo "$COMMITTED" | jq '.event_data.eligible_tickets_snapshot | length')
    RECORDED_WINNER_INDEX=$(echo "$BLOCK" | jq -r '.event_data.winner_index')
    RECORDED_WINNER_TICKET=$(echo "$BLOCK" | jq -r '.event_data.winner_ticket_number')

    # Re-derive winner using sha256-modulo-v1
    DRAW_HASH=$(printf '%s' "$SEED" | sha256sum 2>/dev/null | cut -d' ' -f1 || printf '%s' "$SEED" | shasum -a 256 | cut -d' ' -f1)
    HEX_PREFIX="${DRAW_HASH:0:12}"
    HEX_UPPER=$(echo "$HEX_PREFIX" | tr 'a-f' 'A-F')
    WINNER_INDEX=$(echo "ibase=16; $HEX_UPPER % $TOTAL_ELIGIBLE" | bc)
    WINNER_TICKET=$(echo "$ELIGIBLE_TICKETS" | jq -r ".[$WINNER_INDEX]")

    if [[ "$WINNER_INDEX" != "$RECORDED_WINNER_INDEX" ]]; then
        failure "Block $BLOCK_SEQ: draw winner_index mismatch (expected $WINNER_INDEX, got $RECORDED_WINNER_INDEX)"
        ERRORS=$((ERRORS + 1))
    elif [[ "$WINNER_TICKET" != "$RECORDED_WINNER_TICKET" ]]; then
        failure "Block $BLOCK_SEQ: draw winner_ticket_number mismatch (expected $WINNER_TICKET, got $RECORDED_WINNER_TICKET)"
        ERRORS=$((ERRORS + 1))
    else
        success "Block $BLOCK_SEQ: draw winner independently verified (sha256-modulo-v1)"
    fi

    # Verify commitment hash
    COMMITTED_SEQ=$(echo "$COMMITTED" | jq -r '.sequence')
    COMMITMENT_HASH=$(echo "$COMMITTED" | jq -r '.event_data.commitment_hash // empty')

    if [[ -n "$COMMITMENT_HASH" ]]; then
        COMMITMENT_INPUT="${SEED}${ELIGIBLE_TICKETS}"
        RECOMPUTED_COMMITMENT=$(sha256_hash "$COMMITMENT_INPUT")

        if [[ "$COMMITMENT_HASH" != "$RECOMPUTED_COMMITMENT" ]]; then
            failure "Block $COMMITTED_SEQ: commitment hash mismatch"
            ERRORS=$((ERRORS + 1))
        else
            success "Block $COMMITTED_SEQ: commitment hash verified"
        fi
    fi
done

# --- Summary -----------------------------------------------------------------

echo ""

if [[ "$ERRORS" -eq 0 ]]; then
    echo -e "${GREEN}Chain valid: $BLOCK_COUNT blocks verified, 0 errors${RESET}"
    exit 0
fi

echo -e "${RED}Chain INVALID: $BLOCK_COUNT blocks verified, $ERRORS error(s)${RESET}"
exit 1
bash verify-chain.sh export.json download Baixar
#!/usr/bin/env node
/**
 * Dalanga Transparency Chain Verification Tool
 *
 * A standalone, zero-dependency Node.js script that verifies the integrity of a
 * downloaded Dalanga system chain export file.
 *
 * Requirements: Node.js 14+ (standard library only).
 *
 * Usage:
 *   node verify-chain.js <path-to-export.json>
 *
 * Examples:
 *   node verify-chain.js system-chain-export.json
 *   node verify-chain.js /tmp/chain-export.json
 *
 * What it verifies:
 *   1. Consecutive sequence numbers starting from 0
 *   2. Hash linking: each block's previous_hash matches the preceding block's hash
 *   3. Hash recomputation: re-hashes each block's hash_input and compares to stored hash
 *   4. Genesis block validation: sequence 0 must have previous_hash = null
 *   5. Payload hash verification: re-hashes payload and compares to stored payload_hash
 *   6. Draw fairness: for draw.revealed events, re-derives the winner using the
 *      algorithm_version from event_data and confirms the recorded winner matches
 *
 * Exit codes:
 *   0 = Chain is valid (all checks passed)
 *   1 = Chain is invalid (one or more checks failed)
 *   2 = Usage error (missing file, invalid JSON, etc.)
 */

const crypto = require('crypto');
const fs = require('fs');
const process = require('process');

// ANSI color codes
const GREEN = '\x1b[32m';
const RED = '\x1b[31m';
const RESET = '\x1b[0m';
const BOLD = '\x1b[1m';

function success(message) {
    console.log(`${GREEN}\u2713${RESET} ${message}`);
}

function failure(message) {
    console.log(`${RED}\u2717${RESET} ${message}`);
}

function sha256(input) {
    return crypto.createHash('sha256').update(input, 'utf8').digest('hex');
}

function canonicalJsonEncode(data) {
    if (data === null || typeof data !== 'object') {
        return JSON.stringify(data);
    }
    if (Array.isArray(data)) {
        return '[' + data.map(item => canonicalJsonEncode(item)).join(',') + ']';
    }
    const sortedKeys = Object.keys(data).sort();
    const pairs = sortedKeys.map(key => JSON.stringify(key) + ':' + canonicalJsonEncode(data[key]));
    return '{' + pairs.join(',') + '}';
}

// --- Input Validation -------------------------------------------------------

if (process.argv.length < 3) {
    console.log('Dalanga Transparency Chain Verification Tool');
    console.log('');
    console.log(`Usage: node ${process.argv[1]} <path-to-export.json>`);
    console.log('');
    console.log('Verifies the cryptographic integrity of a chain export file.');
    console.log('For draw events, re-derives the winner to confirm fairness.');
    process.exit(2);
}

const filePath = process.argv[2];

if (!fs.existsSync(filePath)) {
    failure(`File not found: ${filePath}`);
    process.exit(2);
}

let content;
try {
    content = fs.readFileSync(filePath, 'utf8');
} catch (e) {
    failure(`Cannot read file: ${e.message}`);
    process.exit(2);
}

let data;
try {
    data = JSON.parse(content);
} catch (e) {
    failure(`Invalid JSON: ${e.message}`);
    process.exit(2);
}

if (!Array.isArray(data.blocks)) {
    failure('Invalid export format: missing "blocks" array');
    process.exit(2);
}

// --- Chain Verification -----------------------------------------------------

const blocks = data.blocks;
const blockCount = blocks.length;
let errors = 0;

console.log(`${BOLD}Dalanga Transparency Chain Verifier${RESET}`);

if (data.chain) {
    console.log(`Chain: ${data.chain}`);
}

if (data.exported_at) {
    console.log(`Exported: ${data.exported_at}`);
}

console.log(`Blocks: ${blockCount}`);
console.log('');

if (blockCount === 0) {
    success('Chain is empty (0 blocks)');
    process.exit(0);
}

// Chain integrity checks
for (let i = 0; i < blockCount; i++) {
    const block = blocks[i];

    // Check consecutive sequences
    if (block.sequence !== i) {
        failure(`Block ${i}: expected sequence ${i}, got ${block.sequence}`);
        errors++;
        continue;
    }

    // Genesis block validation
    if (i === 0 && block.previous_hash !== null) {
        failure('Block 0: genesis block must have previous_hash = null');
        errors++;
    }

    // Hash linking
    if (i > 0 && block.previous_hash !== blocks[i - 1].hash) {
        failure(`Block ${i}: previous_hash does not match preceding block's hash`);
        errors++;
    }

    // Hash recomputation
    const recomputedHash = sha256(block.hash_input);

    if (block.hash !== recomputedHash) {
        failure(`Block ${i}: hash does not match recomputed hash from hash_input`);
        errors++;
    } else {
        const eventType = block.event_type || 'unknown';
        success(`Block ${i}: hash valid (${eventType})`);
    }
}

// --- Payload Hash Verification ----------------------------------------------

const hasPayloadHashes = blocks.some(b => 'payload_hash' in b);

if (hasPayloadHashes) {
    console.log('');
    console.log(`${BOLD}Payload Hash Verification${RESET}`);
    let payloadChecked = 0;
    let payloadSkipped = 0;

    for (const block of blocks) {
        if (!('payload_hash' in block)) {
            continue;
        }

        if (!('payload' in block)) {
            payloadSkipped++;
            continue;
        }

        payloadChecked++;
        const payloadJson = canonicalJsonEncode(block.payload);
        const recomputedPayloadHash = sha256(payloadJson);

        if (block.payload_hash !== recomputedPayloadHash) {
            failure(`Block ${block.sequence}: payload_hash does not match recomputed hash from payload`);
            errors++;
        } else {
            success(`Block ${block.sequence}: payload hash valid (${block.event_type})`);
        }
    }

    if (payloadSkipped > 0) {
        console.log(`(Skipped ${payloadSkipped} block(s) without payload data \u2014 blocks-only export)`);
    }

    console.log(`Payload hashes checked: ${payloadChecked}, skipped: ${payloadSkipped}`);
}

// --- Draw Event Verification ------------------------------------------------

const committedBlocks = blocks.filter(b => b.event_type === 'draw.committed');

for (const block of blocks) {
    if (block.event_type !== 'draw.revealed') {
        continue;
    }

    const eventData = block.event_data || {};
    const algorithmVersion = eventData.algorithm_version;

    if (!algorithmVersion) {
        failure(`Block ${block.sequence}: draw.revealed missing algorithm_version`);
        errors++;
        continue;
    }

    if (algorithmVersion !== 'sha256-modulo-v1') {
        failure(`Block ${block.sequence}: unknown algorithm version '${algorithmVersion}'`);
        errors++;
        continue;
    }

    // Find matching draw.committed block
    let committed = null;
    for (const cb of committedBlocks) {
        const cbData = cb.event_data || {};
        if (cbData.eligible_tickets_snapshot) {
            committed = cb;
        }
    }

    if (!committed) {
        failure(`Block ${block.sequence}: draw.revealed but no matching draw.committed found`);
        errors++;
        continue;
    }

    const committedData = committed.event_data;
    const seed = eventData.seed;
    const eligibleTickets = committedData.eligible_tickets_snapshot;
    const totalEligible = eligibleTickets.length;

    // Re-derive winner using sha256-modulo-v1
    const drawHash = sha256(seed);
    const hexPrefix = drawHash.substring(0, 12);
    const winnerIndex = parseInt(hexPrefix, 16) % totalEligible;
    const winnerTicketNumber = eligibleTickets[winnerIndex];

    if (winnerIndex !== eventData.winner_index) {
        failure(`Block ${block.sequence}: draw winner_index mismatch (expected ${winnerIndex}, got ${eventData.winner_index})`);
        errors++;
    } else if (winnerTicketNumber !== eventData.winner_ticket_number) {
        failure(`Block ${block.sequence}: draw winner_ticket_number mismatch (expected ${winnerTicketNumber}, got ${eventData.winner_ticket_number})`);
        errors++;
    } else {
        success(`Block ${block.sequence}: draw winner independently verified (sha256-modulo-v1)`);
    }

    // Verify commitment hash
    const commitmentHash = committedData.commitment_hash;

    if (commitmentHash) {
        const recomputedCommitment = sha256(seed + JSON.stringify(eligibleTickets));

        if (commitmentHash !== recomputedCommitment) {
            failure(`Block ${committed.sequence}: commitment hash mismatch`);
            errors++;
        } else {
            success(`Block ${committed.sequence}: commitment hash verified`);
        }
    }
}

// --- Summary ----------------------------------------------------------------

console.log('');

if (errors === 0) {
    console.log(`${GREEN}Chain valid: ${blockCount} blocks verified, 0 errors${RESET}`);
    process.exit(0);
}

console.log(`${RED}Chain INVALID: ${blockCount} blocks verified, ${errors} error(s)${RESET}`);
process.exit(1);
node verify-chain.js export.json download Baixar

O estado da cadeia é periodicamente ancorado em serviços externos, criando provas de timestamp de terceiros.

Todo registro na blockchain usa hooks pós-commit — blocos são criados somente após a transação de negócio primária ser bem-sucedida. Falhas de registro nunca afetam operações primárias.

Todos os dados da blockchain estão disponíveis através de endpoints públicos e sem autenticação — nenhuma conta ou chave de API é necessária. Os endpoints são limitados a 10 requisições por minuto por IP para acesso justo.

Método Endpoint Descrição
GET /api/system-chain/export Exportação completa da cadeia global. Contém todos os blocos registrados na plataforma. Use ?after={sequence} para downloads incrementais — a primeira chamada retorna a cadeia completa, chamadas subsequentes retornam apenas blocos novos.
GET /api/system-chain/verify-data Dados de verificação leves para a cadeia global. Retorna apenas hashes e números de sequência — ideal para verificações automatizadas de integridade. Suporta ?after={sequence} para polling incremental.
GET /api/system-chain/verify-tools Manifesto das ferramentas de verificação. Lista todos os scripts de verificação disponíveis com checksums, tamanhos e URLs de download.
GET /api/system-chain/verify-tool/{lang} Download de um script de verificação por idioma. Valores aceitos: php, python, bash, node.

Exemplo:

curl -s https://dalanga.com/api/system-chain/export -o chain.json

# Incremental download (only new blocks since sequence 42):
curl -s "https://dalanga.com/api/system-chain/export?after=42" -o chain-update.json

Esses endpoints são projetados para acesso contínuo e programático — construa scripts de monitoramento automatizado, integre com ferramentas de auditoria de terceiros ou desenvolva seu próprio pipeline de verificação. Esta é a base para um futuro ecossistema aberto onde qualquer pessoa pode verificar independentemente cada rifa na Dalanga.