README
- Mention social feed in the one-line description and feature bullets
- Add relay + feed endpoint tables to the API overview (was
previously empty on messaging)
- List media/ package in the repo structure
docs/api/
- New docs/api/feed.md: full reference for /feed/publish, fetch,
stats, view, author, timeline, trending, foryou, hashtag; all
on-chain CREATE_POST / DELETE_POST / FOLLOW / LIKE payloads;
fee economics; server-side scrubbing contract.
- docs/api/relay.md rewritten: /relay/broadcast is now the primary
E2E path with a complete envelope schema; /relay/send kept but
flagged ⚠ NOT E2E; DELETE /relay/inbox/{id} documented with the
new Ed25519 signed-auth body.
- docs/api/README.md index: added feed.md row.
docs/architecture.md
- L2 Transport layer description updated to include the feed
mailbox alongside the 1:1 relay mailbox.
- New "Социальная лента (v2.0.0)" section right after the 1:1
message flow: ASCII diagram of publish + on-chain commit +
timeline fetch, economic summary, metadata-scrub summary.
docs/node/README.md
- Removed stale chan:/chan-member: keys from the BadgerDB schema
reference; replaced with the v2.0.0 feed keys (post:,
postbyauthor:, follow:, followin:, like:, likecount:).
docs/update-system.md
- Example features[] array updated to match the actual node output
(channels_v1 removed, feed_v2 / media_scrub / relay_broadcast added).
Node feature flags
- api_well_known_version.go: dropped channels_v1 tag (the
/api/channels/:id endpoint was removed in the feed refactor);
added feed_v2, media_scrub, relay_broadcast so clients can
feature-detect the v2.0.0 surface.
- Comment example updated channels_v2/v1 → feed_v3/v2.
Client
- CLIENT_REQUIRED_FEATURES expanded to include the v2.0.0 feature
flags the client now depends on (feed_v2, media_scrub,
relay_broadcast); checkNodeVersion() will flag older nodes as
unsupported and surface an upgrade prompt.
All 7 Go test packages green; tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
254 lines
13 KiB
Markdown
254 lines
13 KiB
Markdown
# Архитектура DChain
|
||
|
||
## Обзор
|
||
|
||
DChain — это L1-блокчейн для децентрализованного мессенджера + социальной ленты. Архитектура разделена на четыре слоя:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ L3 Application — messaging, social feed, usernames, │
|
||
│ auctions, escrow │
|
||
│ (Smart contracts: username_registry, governance, auction, │
|
||
│ escrow; native feed events; deployed on-chain) │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ L2 Transport — relay mailbox (1:1 E2E) + │
|
||
│ feed mailbox (public posts + attachments)│
|
||
│ (relay/, media scrubber, GossipSub envelopes, RELAY_PROOF) │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ L1 Chain — PBFT consensus, WASM VM, BadgerDB │
|
||
│ (blockchain/, consensus/, vm/, identity/) │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ L0 Network — libp2p, GossipSub, DHT, mDNS │
|
||
│ (p2p/) │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## Консенсус (PBFT)
|
||
|
||
**Алгоритм:** Practical Byzantine Fault Tolerance, кворум 2/3.
|
||
|
||
**Фазы:**
|
||
```
|
||
Leader Validator-2 Validator-3
|
||
│── PRE-PREPARE ──▶│ │
|
||
│── PRE-PREPARE ────────────────────────▶ │
|
||
│◀─ PREPARE ───────│ │
|
||
│◀─ PREPARE ────────────────────────────── │
|
||
│── COMMIT ────────▶│ │
|
||
│── COMMIT ──────────────────────────────▶ │
|
||
│◀─ COMMIT ────────│ │
|
||
│◀─ COMMIT ────────────────────────────── │
|
||
AddBlock()
|
||
```
|
||
|
||
**Свойства:**
|
||
- Safety при ≤ f Byzantine нодах где N ≥ 3f+1
|
||
- Текущий testnet: N=2 валидатора, f=0 (узел node3 — relay-only observer)
|
||
- View-change при недоступном лидере: таймаут 10 секунд
|
||
|
||
**Блок-производство:**
|
||
- Fast ticker (500 ms) — при наличии транзакций в mempool
|
||
- Idle ticker (5 s) — пустые блоки для heartbeat и синхронизации
|
||
|
||
**Ключевые файлы:**
|
||
```
|
||
consensus/engine.go — PBFT engine
|
||
consensus/msg.go — ConsensusMsg типы (PRE-PREPARE, PREPARE, COMMIT, VIEW-CHANGE)
|
||
```
|
||
|
||
---
|
||
|
||
## Хранилище (BadgerDB)
|
||
|
||
Весь state хранится в BadgerDB (LSM-дерево, pure Go).
|
||
|
||
**Пространства ключей:**
|
||
|
||
| Префикс | Тип | Описание |
|
||
|---------|-----|---------|
|
||
| `block:<index_20d>` | JSON | Блоки по индексу |
|
||
| `height` | uint64 JSON | Текущая высота |
|
||
| `balance:<pubkey>` | uint64 JSON | Балансы токенов |
|
||
| `id:<pubkey>` | JSON | Identity (RegisterKey payload) |
|
||
| `validator:<pubkey>` | presence | Активный сет валидаторов |
|
||
| `relay:<pubkey>` | JSON | Зарегистрированные relay-ноды |
|
||
| `contract:<id>` | JSON | ContractRecord (метаданные + WASM) |
|
||
| `cstate:<id>:<key>` | raw bytes | Состояние контракта |
|
||
| `clog:<id>:<height_20d>:<seq_05d>` | JSON | Логи контракта |
|
||
| `rep:<pubkey>` | JSON | Репутация (blocks, relays, slashes) |
|
||
| `contact_in:<to>:<from>` | JSON | Входящие contact requests |
|
||
| `mail:<x25519>:<ts>:<id>` | JSON | Relay mailbox (TTL 7 дней) |
|
||
|
||
**Две отдельные БД:**
|
||
- `--db ./chaindata` — chain state (consensus state machine)
|
||
- `--mailbox-db ./mailboxdata` — relay mailbox (отдельная изоляция)
|
||
|
||
---
|
||
|
||
## P2P сеть (libp2p)
|
||
|
||
**Компоненты:**
|
||
- **Transport:** TCP `/ip4/0.0.0.0/tcp/4001`
|
||
- **Identity:** Ed25519 peer key (вывод из node identity)
|
||
- **Discovery:** mDNS (локалка) + Kademlia DHT (WAN)
|
||
- **Pub/Sub:** GossipSub с тремя топиками:
|
||
|
||
| Топик | Содержимое |
|
||
|-------|-----------|
|
||
| `dchain/tx/v1` | Транзакции (gossip) |
|
||
| `dchain/blocks/v1` | Готовые блоки (gossip от лидера) |
|
||
| `dchain/relay/v1` | Relay envelopes (зашифрованные сообщения) |
|
||
|
||
- **Direct streams:** PBFT consensus messages (pre-prepare/prepare/commit/view-change) идут напрямую между валидаторами через `/dchain/consensus/1.0.0` протокол
|
||
- **Sync:** block range sync по `/dchain/sync/1.0.0` при подключении нового пира
|
||
|
||
---
|
||
|
||
## WASM Virtual Machine
|
||
|
||
**Runtime:** wazero v1.7.3, interpreter mode (детерминированный на всех платформах).
|
||
|
||
**Жизненный цикл контракта:**
|
||
|
||
```
|
||
DEPLOY_CONTRACT tx
|
||
├── validate: wazero.CompileModule() — если ошибка, tx отклоняется
|
||
├── contractID = hex(sha256(deployerPubKey || wasmBytes))[:16]
|
||
├── BadgerDB: contract:<id> → ContractRecord{WASMBytes, ABI, ...}
|
||
└── state: cstate:<id>:* — изначально пусто
|
||
|
||
CALL_CONTRACT tx
|
||
├── ABI validation: метод существует, число аргументов совпадает
|
||
├── pre-charge: tx.Fee + gasLimit × gasPrice
|
||
├── vm.Call(contractID, wasmBytes, method, argsJSON, gasLimit, hostEnv)
|
||
│ ├── compile (cached) + instrument (gas_tick в loop headers)
|
||
│ ├── register "env" host module (14 функций)
|
||
│ ├── [optional] wasi_snapshot_preview1 (для TinyGo контрактов)
|
||
│ └── fn.Call(ctx) → gasUsed, error
|
||
├── refund: (gasLimit - gasUsed) × gasPrice → обратно sender
|
||
└── logs: clog:<id>:<height>:<seq> → BadgerDB
|
||
```
|
||
|
||
**Gas модель:** каждый вызов функции (WASM или host) = 100 gas units.
|
||
`gasCost (µT) = gasUsed × gasPrice` (gasPrice управляется governance или константа 1 µT).
|
||
|
||
**Типы контрактов:**
|
||
- **Binary WASM** — написаны на Go через кодогенераторы (`contracts/*/gen/main.go`)
|
||
- **TinyGo WASM** — написаны на Go, компилируются с `tinygo -target wasip1`
|
||
|
||
---
|
||
|
||
## Экономика
|
||
|
||
**Supply:** Фиксированный. Genesis-блок минтит **21 000 000 T** на ключ node1. Последующей эмиссии нет.
|
||
|
||
**Unit:** µT (микро-токен). 1 T = 1 000 000 µT.
|
||
|
||
**Доходы валидаторов:** только комиссии из транзакций блока (`TotalFees`). Без блок-реварда.
|
||
|
||
**Комиссии:**
|
||
| Операция | Минимальная fee |
|
||
|---------|----------------|
|
||
| Все транзакции | 1 000 µT (MinFee) |
|
||
| CONTACT_REQUEST | tx.Amount → recipient (anti-spam) |
|
||
| DEPLOY_CONTRACT | 10 000 µT |
|
||
| CALL_CONTRACT | MinFee + gasUsed × gasPrice |
|
||
| RELAY_PROOF | sender → relay node (произвольно) |
|
||
|
||
**Governance:** gas_price, relay_fee и другие параметры можно менять on-chain через governance-контракт без хардфорка.
|
||
|
||
---
|
||
|
||
## Relay (E2E мессенджер)
|
||
|
||
**Шифрование:** NaCl box (X25519 Diffie-Hellman + XSalsa20 + Poly1305).
|
||
|
||
**Ключи:** каждый Identity имеет два ключа:
|
||
- Ed25519 (подпись транзакций, chain identity)
|
||
- X25519 (вывод из Ed25519 seed, шифрование сообщений)
|
||
|
||
**Поток сообщения:**
|
||
```
|
||
Alice node1 (relay) Bob
|
||
│ │ │
|
||
│── seal(msg, bob.X25519) ──▶ │ │
|
||
│ POST /relay/broadcast │ │
|
||
│ │── gossip envelope ──▶ │
|
||
│ │ store mailbox │
|
||
│ │ (TTL 7 days) │
|
||
│ │ │
|
||
│ │◀── GET /relay/inbox ──│
|
||
│ │ │── open(envelope)
|
||
│ │ │ → plaintext
|
||
```
|
||
|
||
**Anti-spam:**
|
||
- Первый контакт — платный (CONTACT_REQUEST tx, fee идёт получателю)
|
||
- Envelope: max 64 KB, max 500 envelopes на получателя (FIFO)
|
||
- RELAY_PROOF: подписанное доказательство доставки, fee снимается со sender и кредитуется relay
|
||
|
||
---
|
||
|
||
## Социальная лента (v2.0.0)
|
||
|
||
Публичные посты в Twitter/VK-стиле. Заменила channel-модель (каналы
|
||
удалены полностью). Живёт гибридно — метаданные on-chain, тела в relay
|
||
feed-mailbox:
|
||
|
||
```
|
||
Alice node1 (hosting relay) Bob
|
||
│ │ │
|
||
│─ POST /feed/publish ──────▶│ │
|
||
│ (body + EXIF-scrub) │ │
|
||
│ │ store in feed-mailbox │
|
||
│ │ (TTL 30 days) │
|
||
│ │ │
|
||
│◀── response: content_hash, │ │
|
||
│ estimated_fee_ut, id │ │
|
||
│ │ │
|
||
│─ CREATE_POST tx ──────────▶│── PBFT commit ──────────▶ │
|
||
│ (fee = 1000 + size × 1) │ │
|
||
│ │ on-chain: post:<id> │
|
||
│ │ │
|
||
│ │ │─ GET /feed/timeline
|
||
│ │◀── merge followed authors │ (from chain)
|
||
│ │ │
|
||
│ │── GET /feed/post/{id} ───▶│
|
||
│ │ (body from mailbox) │
|
||
```
|
||
|
||
**Экономика:**
|
||
- Автор платит `BasePostFee(1000) + size × PostByteFee(1)` µT
|
||
- Вся плата уходит `hosting_relay` пубкею — компенсация за хранение
|
||
- `MaxPostSize = 256 KiB` — hard cap, защищает мейлбокс от abuse
|
||
|
||
**Метаданные:**
|
||
- EXIF/GPS/camera-info удаляется обязательно на сервере (in-proc для
|
||
изображений, через FFmpeg-сайдкар для видео)
|
||
- Лайки / follows — on-chain транзакции (provable + anti-Sybil fee)
|
||
- Просмотры — off-chain counter в relay (on-chain было бы абсурдно)
|
||
- Хэштеги — авто-индекс при publish, inverted-index в BadgerDB
|
||
|
||
Детали — [api/feed.md](api/feed.md).
|
||
|
||
---
|
||
|
||
## Динамические валидаторы
|
||
|
||
Сет валидаторов хранится on-chain в `validator:<pubkey>`. Любой текущий валидатор может добавить или убрать другого (ADD_VALIDATOR / REMOVE_VALIDATOR tx). После commit такого блока PBFT-движок перезагружает сет без рестарта ноды.
|
||
|
||
**Ключевые файлы:**
|
||
```
|
||
blockchain/chain.go — state machine, applyTx, VMHostEnv
|
||
consensus/engine.go — PBFT, UpdateValidators()
|
||
vm/vm.go — wazero runtime, NewVM()
|
||
vm/host.go — host module "env" (14 функций)
|
||
vm/gas.go — gas counter, Remaining()
|
||
relay/mailbox.go — BadgerDB TTL mailbox
|
||
relay/crypto.go — NaCl seal/open
|
||
p2p/host.go — libp2p host, GossipSub
|
||
node/api_routes.go — HTTP API routing
|
||
```
|