11 KiB
Montana Protocol — P2P Network Specification
Техническая спецификация пиринговой сети
Version: 2.0 Status: MAINNET Date: 2026-01-23 Authors: Alejandro Montana
Abstract
Настоящий документ описывает архитектуру пиринговой сети Montana Protocol. Сеть обеспечивает распространение подписей присутствия, выбор активного мастера и защиту от изоляции узлов.
1. Архитектура сети
1.1 Топология
Montana Protocol использует фиксированную топологию из 5 узлов:
┌─────────────┐
│ amsterdam │ ← PRIMARY (позиция 0)
│ 72.56.102.240│
└──────┬──────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌─────▼────┐
│ moscow │ │ almaty │ │ spb │
│176.124..│ │91.200...│ │188.225...│
└────┬────┘ └────┬────┘ └────┬─────┘
│ │ │
└────────────────┼────────────────┘
│
┌──────▼──────┐
│ novosibirsk │
│147.45.147...│
└─────────────┘
1.2 Типы узлов
| Тип | Описание | Реализация |
|---|---|---|
| Full Node | Полный узел сети с Telegram polling | junomontanaagibot.py |
| Health Server | HTTP endpoint для проверки здоровья | leader_election.py:8889 |
1.3 Порты
| Порт | Протокол | Назначение |
|---|---|---|
| 22 | SSH | Администрирование |
| 8889 | HTTP | Health check endpoint |
| 443 | HTTPS | Fallback проверка |
2. Leader Election Protocol
2.1 Алгоритм выбора мастера
Детерминированный выбор мастера на основе позиции в цепочке:
# leader_election.py:326-349
BOT_CHAIN = [
("amsterdam", "72.56.102.240"), # позиция 0
("moscow", "176.124.208.93"), # позиция 1
("almaty", "91.200.148.93"), # позиция 2
("spb", "188.225.58.98"), # позиция 3
("novosibirsk", "147.45.147.247"), # позиция 4
]
def am_i_the_master():
for name, ip in BOT_CHAIN:
if name == my_node_name:
return True # Я первый живой — я мастер
if check_node_health(ip):
return False # Узел выше меня жив
return False
2.2 Health Check Protocol
HTTP запрос к /health endpoint:
# leader_election.py:102-134
def check_node_health(ip: str) -> bool:
try:
url = f"http://{ip}:8889/health"
response = requests.get(url, timeout=5)
return response.status_code == 200
except:
return False
Response format:
{
"status": "healthy",
"node": "moscow",
"uptime": 3600,
"is_master": false
}
2.3 Failover Timing
| Событие | Время |
|---|---|
| Health check interval | 5 секунд |
| Request timeout | 5 секунд |
| Max failover time | < 10 секунд |
| Startup delay | 7-15 секунд (рандом) |
3. Message Types
3.1 Telegram Polling
Только мастер-узел выполняет polling Telegram API:
# junomontanaagibot.py
async def start_polling():
if not am_i_the_master():
return # Standby режим
await application.run_polling(
drop_pending_updates=True,
allowed_updates=Update.ALL_TYPES
)
3.2 Presence Proof
Подпись присутствия (ML-DSA-65):
# time_bank.py:271-327
message = f"MONTANA_PRESENCE_V1:{timestamp}:{prev_hash}:{pubkey}:{t2_index}"
signature = ML_DSA_65.sign(private_key, message.encode())
proof_hash = SHA256(message || signature)
| Поле | Размер | Описание |
|---|---|---|
| version | 20 B | "MONTANA_PRESENCE_V1" |
| timestamp | 8 B | Unix timestamp |
| prev_hash | 64 B | SHA256 предыдущего proof |
| pubkey | 1952 B | ML-DSA-65 public key |
| t2_index | 8 B | Номер τ₂ слайса |
| signature | 3309 B | ML-DSA-65 подпись |
4. Защита от Eclipse
4.1 Стратегия
Eclipse-атака — изоляция узла от честной сети. Защита обеспечивается:
- Фиксированная топология — узлы знают друг друга заранее
- Множественные проверки — ping + TCP fallback
- Географическое распределение — 5 регионов
4.2 Multi-method Health Check
# leader_election.py:102-134
def check_node_health(ip: str) -> bool:
# 1. HTTP health endpoint
try:
response = requests.get(f"http://{ip}:8889/health", timeout=5)
if response.status_code == 200:
return True
except:
pass
# 2. Fallback: TCP port check (SSH)
try:
sock = socket.create_connection((ip, 22), timeout=5)
sock.close()
return True
except:
pass
# 3. Fallback: TCP port check (HTTPS)
try:
sock = socket.create_connection((ip, 443), timeout=5)
sock.close()
return True
except:
pass
return False
5. Защита от атак
5.1 Random Failover
При обнаружении атаки цепочка перемешивается:
# leader_election.py:395-430
def shuffle_chain_on_attack():
if not attack_detector.is_under_attack():
return
shuffled = list(BOT_CHAIN)
random.shuffle(shuffled)
healthy_nodes = [
(name, ip) for name, ip in shuffled
if check_node_health(ip)
]
BOT_CHAIN = healthy_nodes # Новый порядок
Пример:
Нормальный режим:
amsterdam → moscow → almaty → spb → novosibirsk
После атаки:
spb → novosibirsk → almaty → moscow
(amsterdam исключён как атакованный)
5.2 Attack Detection Metrics
# leader_election.py:190-232
class AttackDetector:
cpu_threshold = 80.0 # %
network_threshold = 100 MB/s # входящий трафик
max_failures = 10 # подряд
response_time_threshold = 5.0 # секунд
6. Синхронизация состояния
6.1 Breathing Sync
Git-синхронизация каждые 12 секунд:
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Inhale │────▶│ Work │────▶│ Exhale │
│git pull │ │ 12 sec │ │git push │
└─────────┘ └─────────┘ └─────────┘
▲ │
└───────────────────────────────┘
Исходный код: breathing_sync.py
6.2 Синхронизируемые данные
| Данные | Путь | Формат |
|---|---|---|
| База данных | data/montana.db | SQLite |
| События | data/events.jsonl | JSON Lines |
| Конфигурация | *.py | Python |
7. Сетевые метрики
7.1 Health Status
# junomontanaagibot.py:997-1051
def health_check() -> Dict:
return {
"status": "healthy" | "degraded" | "under_attack",
"uptime": int,
"metrics": {
"cpu_percent": float, # скользящее среднее
"memory_percent": float,
"disk_percent": float,
"active_connections": int,
"blocked_ips": int,
"suspicious_ips": int
}
}
7.2 Пороги статусов
| Статус | Условие |
|---|---|
| healthy | cpu < 90% AND mem < 90% AND suspicious < 5 |
| degraded | (cpu > 90% OR mem > 90%) × 3 подряд |
| under_attack | attack_detector.under_attack = True |
8. Деплой и обновление
8.1 Rolling Deploy
# deploy_nodes.sh
./deploy_nodes.sh # По одному узлу, 20 сек между ними
./deploy_nodes.sh --fast # Все сразу (downtime!)
./deploy_nodes.sh --node X # Только узел X
8.2 Порядок деплоя
- Обновить amsterdam (PRIMARY)
- Ждать 20 секунд (failover time)
- Обновить moscow
- Ждать 20 секунд
- ... остальные узлы
8.3 Верификация
# Проверка хэшей на всех узлах
for ip in 72.56.102.240 176.124.208.93 ...; do
ssh root@$ip "md5sum /root/bot/junomontanaagibot.py"
done
Ожидаемый результат: все хэши идентичны.
9. Диагностика
9.1 Проверка статуса узла
ssh root@IP "systemctl status junona"
ssh root@IP "journalctl -u junona -n 50 --no-pager"
ssh root@IP "curl localhost:8889/health"
9.2 Проверка leader election
ssh root@IP "journalctl -u junona | grep -i 'master\|standby'"
9.3 Проверка синхронизации
for ip in 72.56.102.240 176.124.208.93 91.200.148.93 188.225.58.98 147.45.147.247; do
echo "=== $ip ==="
ssh root@$ip "md5sum /root/bot/junomontanaagibot.py | cut -d' ' -f1"
done
10. Ограничения
| Ограничение | Описание | Mitigation |
|---|---|---|
| Фиксированная топология | Нельзя добавить узел динамически | Требует деплой |
| Single Telegram Token | Один токен на всю сеть | Leader Election |
| Git-based sync | Не подходит для high-frequency данных | Event Sourcing |
Заключение
P2P сеть Montana Protocol обеспечивает:
- Отказоустойчивость — 5 узлов, автоматический failover
- Безопасность — ML-DSA-65, Random Failover при атаке
- Консистентность — Breathing Sync через Git
- Мониторинг — Health endpoints, AtlantGuard
Сеть функционирует в MAINNET режиме с января 2026.
Alejandro Montana
Montana Protocol P2P Specification v2.0
2026-01-23