# Single Source of Truth — VPN-сеть Montana Версия: **2026-05-19** ## Принцип Вся канонически верифицируемая правда о состоянии VPN-сети живёт в **одном append-only signed event log**: ``` https://montana.quest/vpn/events.jsonl ``` Каждая строка — событие, индивидуально подписанное **ed25519**: ```jsonl {"data":{...},"seq":N,"sig":"ed25519:...","ts":"2026-05-19T19:00:00Z","type":"node_register"} ``` **Свойства:** - **Append-only:** запись только в конец, прошлые события не переписываются. - **Подписанные:** каждое событие проверяется публичным ключом `d9a8bf07871d35c8e85f7de4a9b62896c330ba0987732468515c7bda8bb4adde`. - **Монотонный seq:** счётчик никогда не убывает, гэпы запрещены. - **Pure-function state:** state = replay(events). ## Типы событий | type | data | когда | |---|---|---| | `node_register` | `{alias, ip, country, label}` | admin регистрирует узел через /vpn/node/register | | `node_deregister` | `{alias, ip}` | узел остановлен (xray ExecStopPost) | | `node_online` | `{alias, ip}` | orchestrator watchdog: probe OK после offline | | `node_offline` | `{alias, ip}` | orchestrator watchdog: 2 probe fails подряд | | `unique_user` | `{ip_hash}` | новый sha256(client_IP) в логе xray | | `metric` | произвольное | периодические метрики (нагрузка, throughput) | | `checkpoint` | `{seq_range, merkle}` | каждые 1000 событий (план) | ## Derived state `https://montana.quest/vpn/state.json` — кешированный результат `build_state(events)`. Любой может перепостроить и сравнить. ```json { "head_seq": 1502, "head_ts": "2026-05-19T19:25:30Z", "built_at": "...", "nodes": { "helsinki": {"online": true, "ip": "91.132.142.42", "country": "FI", ...}, "frankfurt": {"online": true, ...}, "newyork": {"online": true, ...} }, "unique_users": 957, "unique_users_merkle": "...", "pubkey_hex": "d9a8bf07...", "event_log_url": "https://montana.quest/vpn/events.jsonl" } ``` `state.json` rebuilds каждые 30 секунд через `montana-state-builder.timer` на Moscow. ## Что НЕ публикуется - IP-адреса пользователей (это PII). В события `unique_user` идёт **только sha256 IP** — не обратимо без brute-force на 32-битное IPv4 пространство (~4 сек на rainbow tabe). - Чтобы усложнить brute-force, в roadmap — добавить **secret salt** с публикацией с задержкой 7 дней. ## Архитектура emitters ``` ┌─────────────────────────┐ │ /opt/montana-vpn-stats │ │ /event_log.py │ │ (sign + append) │ └────────────┬────────────┘ │ ┌────────────────────────────┼────────────────────────────┐ │ │ │ orchestrator watchdog xray-stats collector admin /register (online/offline transitions) (new unique IPs) (manual events) │ │ │ └────────────────────────────▼────────────────────────────┘ │ /var/www/montana_quest/vpn/events.jsonl │ ▼ montana-state-builder.timer (30s) │ /var/www/montana_quest/vpn/state.json │ ▼ сайт + /vpn/sub + /vpn/node/uptime (читают state.json) ``` ## Гарантии | Гарантия | Как доказывается | |---|---| | Число уникальных пользователей не подделано | каждое событие `unique_user` подписано; state.json содержит merkle root; replay воспроизводит число | | Узел не «фейково онлайн» | переходы online↔offline — отдельные подписанные события с timestamp | | История не переписана | append-only; seq монотонный без гэпов; любой имеет полный лог | | Нельзя backdate | timestamp на каждом событии; запланировано daily anchoring через OpenTimestamps | ## Что НЕ гарантируется (пока) - **Forced inclusion:** мы можем замедлить добавление события в лог. Защита: автоматический rebuild каждые 30 секунд. - **Privatekey compromise:** если ключ утечёт, можно подделать события. Защита: privateKey 600 root на Moscow. - **Tampering архивных событий:** теоретически root доступом на Moscow можно переписать `events.jsonl`. **Защита roadmap:** ежедневный snapshot хеша всего лога в Bitcoin через OpenTimestamps — нельзя backdate. ## Аудит Любой может проверить single-source-of-truth: ```bash bash Montana/Node/External-Audit/scripts/verify-state.sh ``` Этот скрипт: 1. Скачивает `events.jsonl` и `state.json`. 2. Проверяет ed25519-подпись каждого события. 3. Проверяет монотонность seq без гэпов. 4. Replay events до `head_seq` из state.json. 5. Сравнивает результат replay со state.json: `head_seq`, `unique_users`, `merkle root`, `nodes online/offline`. Если хотя бы один тест провалится — мы лжём. ## Сейчас зелёные тесты ``` ✓ все 1531 events подписаны валидно, seq непрерывен ✓ replay matches claimed state: head_seq=1502, nodes=3, unique_users=957 === ВСЕ ПРОВЕРКИ ЗЕЛЁНЫЕ === ``` ## Roadmap - **P1:** daily checkpoint в Bitcoin через OpenTimestamps. Дописать `transparency.md`. - **P2:** мульти-эмиттер — каждый узел независимо подписывает свои события + threshold-signature (2 of 3). Устраняет single trust на Moscow privateKey. - **P3:** GraphQL-like derivation API — клиенты запрашивают subset state через `?fields=...`. - **P4:** Public mirror лога на IPFS/GitHub raw — анти-цензура.