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>
13 KiB
Архитектура 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.
Динамические валидаторы
Сет валидаторов хранится 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