406 lines
11 KiB
Markdown
406 lines
11 KiB
Markdown
# 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 Алгоритм выбора мастера
|
||
|
||
Детерминированный выбор мастера на основе позиции в цепочке:
|
||
|
||
```python
|
||
# 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:
|
||
|
||
```python
|
||
# 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:**
|
||
```json
|
||
{
|
||
"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:
|
||
|
||
```python
|
||
# 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):
|
||
|
||
```python
|
||
# 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-атака — изоляция узла от честной сети. Защита обеспечивается:
|
||
|
||
1. **Фиксированная топология** — узлы знают друг друга заранее
|
||
2. **Множественные проверки** — ping + TCP fallback
|
||
3. **Географическое распределение** — 5 регионов
|
||
|
||
### 4.2 Multi-method Health Check
|
||
|
||
```python
|
||
# 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
|
||
|
||
При обнаружении атаки цепочка перемешивается:
|
||
|
||
```python
|
||
# 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
|
||
|
||
```python
|
||
# 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](../Бот/breathing_sync.py)
|
||
|
||
### 6.2 Синхронизируемые данные
|
||
|
||
| Данные | Путь | Формат |
|
||
|--------|------|--------|
|
||
| База данных | data/montana.db | SQLite |
|
||
| События | data/events.jsonl | JSON Lines |
|
||
| Конфигурация | *.py | Python |
|
||
|
||
---
|
||
|
||
## 7. Сетевые метрики
|
||
|
||
### 7.1 Health Status
|
||
|
||
```python
|
||
# 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
|
||
|
||
```bash
|
||
# deploy_nodes.sh
|
||
|
||
./deploy_nodes.sh # По одному узлу, 20 сек между ними
|
||
./deploy_nodes.sh --fast # Все сразу (downtime!)
|
||
./deploy_nodes.sh --node X # Только узел X
|
||
```
|
||
|
||
### 8.2 Порядок деплоя
|
||
|
||
1. Обновить amsterdam (PRIMARY)
|
||
2. Ждать 20 секунд (failover time)
|
||
3. Обновить moscow
|
||
4. Ждать 20 секунд
|
||
5. ... остальные узлы
|
||
|
||
### 8.3 Верификация
|
||
|
||
```bash
|
||
# Проверка хэшей на всех узлах
|
||
for ip in 72.56.102.240 176.124.208.93 ...; do
|
||
ssh root@$ip "md5sum /root/bot/junomontanaagibot.py"
|
||
done
|
||
```
|
||
|
||
**Ожидаемый результат:** все хэши идентичны.
|
||
|
||
---
|
||
|
||
## 9. Диагностика
|
||
|
||
### 9.1 Проверка статуса узла
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
ssh root@IP "journalctl -u junona | grep -i 'master\|standby'"
|
||
```
|
||
|
||
### 9.3 Проверка синхронизации
|
||
|
||
```bash
|
||
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 обеспечивает:
|
||
|
||
1. **Отказоустойчивость** — 5 узлов, автоматический failover
|
||
2. **Безопасность** — ML-DSA-65, Random Failover при атаке
|
||
3. **Консистентность** — Breathing Sync через Git
|
||
4. **Мониторинг** — Health endpoints, AtlantGuard
|
||
|
||
Сеть функционирует в MAINNET режиме с января 2026.
|
||
|
||
---
|
||
|
||
```
|
||
Alejandro Montana
|
||
Montana Protocol P2P Specification v2.0
|
||
2026-01-23
|
||
```
|