# DChain CHANGELOG Consolidated record of what landed. Replaces the now-deleted `REFACTOR_PLAN.md`, `NODE_ONBOARDING.md`, and `ROADMAP.md` — every numbered item there is either shipped (listed below) or explicitly deferred. --- ## Production-ready stack (shipped) ### Consensus & chain - **PBFT multi-sig validator admission**. `ADD_VALIDATOR` requires ⌈2/3⌉ cosigs from the current set + candidate must have ≥ `MinValidatorStake` (1 T) locked via STAKE. Same gate on forced `REMOVE_VALIDATOR`; self- removal stays unilateral. - **Equivocation slashing**. `SLASH` tx with `reason=equivocation` carries both conflicting PREPARE/COMMIT messages as evidence; `ValidateEquivocation` verifies on-chain — any node can report, no trust. Offender's stake is burned and they're evicted from the set. - **Liveness tracking**. PBFT records per-validator last-seen seqNum; `LivenessReport()` + `MissedBlocks()` surface stalemates. Exposed via `dchain_max_missed_blocks` Prometheus gauge. - **Fair mempool**. Per-sender FIFO queues drained round-robin into proposals; one spammer can't starve others. - **Block-reward fix**. Synthetic BLOCK_REWARD transactions use `From=""` so self-validators don't appear to pay themselves in history. ### Storage & stability - **Re-entrant-deadlock fix**. Dedicated `configMu` and `nativeMu` separate from `c.mu` — applyTx can safely read config/native registry while `AddBlock` holds the write lock. - **BadgerDB tuning**. `WithValueLogFileSize(64 MiB)` + `WithNumVersionsToKeep(1)` + background `StartValueLogGC` every 5 minutes + one-shot `CompactNow()` at startup. Reclaims gigabytes from upgraded nodes automatically. - **`TipIndex()`** — lock-free reads so `/api/blocks` and `/api/txs/recent` never hang even when `AddBlock` is stuck. - **Chronological tx index** (`txchron::`). `RecentTxs` runs in O(limit) instead of O(empty blocks) — important when tps is low. - **WASM VM timeout + `WithCloseOnContextDone`**. Any contract call aborts at 30 s hard cap; gas metering evasion can no longer freeze the chain. ### Native contracts - **`native:username_registry`** (v2.1.0). Replaces WASM registry — 100× faster, no VM failure surface. `register(name)` requires exact `tx.Amount = 10 000 µT` (burned, visible in history). Min length 4, lowercase `a-z 0-9 _ -`, first char letter, reserved words blacklist. - **Native dispatcher** in `applyTx` → checks `native:*` IDs first, falls through to WASM VM otherwise. ABI JSON + contract metadata surfaced via `/api/contracts/:id` with `"native": true` flag. - **Well-known auto-discovery**. `/api/well-known-contracts` returns canonical contract IDs indexed by ABI name; native always wins. Client auto-syncs on connect. ### WebSocket gateway (push-based UX) - **`GET /api/ws`** — persistent bidirectional JSON-framed connection. - **Topics**: `blocks`, `tx`, `addr:`, `inbox:`, `contract_log`, `contract:`, `typing:`. - **`auth` op**. Client signs server-issued nonce with Ed25519; hub binds connection to pubkey so scoped subscriptions (`addr:*`, `inbox:*`, `typing:*`) are accepted only for owned identities. - **`submit_tx` op**. Low-latency tx submission with correlated `submit_ack` frame; removes the HTTP round-trip. Client falls back to POST `/api/tx` automatically if WS is down. - **Typing indicators**. Ephemeral `typing` op, authenticated, scoped to recipient. Mobile client shows "печатает…" in chat header. - **Per-connection quotas**. Max 10 connections / IP, 32 subs / connection. Bounded outbox drops oldest on overflow with `{event:"lag"}` notice. - **Fanout mirrors SSE**. `eventBus` dispatches to SSE + WS + future consumers from one emit site. ### Relay mailbox - **Push notifications**. `Mailbox.SetOnStore` hook → `wsHub.EmitInbox(...)` on every fresh envelope. Client's `useMessages` subscribes instead of polling every 3 s. - **Relay TTL**. `REGISTER_RELAY` and HEARTBEAT (from registered relays) refresh a `relayhb:` timestamp; `/api/relays` filters anything older than 2 hours. Stale relays are delisted automatically. ### Node onboarding - **`--join `** — multi-seed bootstrap. Tries each URL in order, persists the live list to `/seeds.json` on first success so subsequent restarts don't need the CLI flag. - **`/api/network-info`** — one-shot payload (chain_id, genesis_hash, validators, peers, contracts, stats) for joiners. - **`/api/peers`** — live libp2p peer list with multiaddrs. - **Genesis-hash verification**. A node with expected hash aborts if its local block 0 doesn't match (protection against forged seeds). Override with `--allow-genesis-mismatch` for migrations. - **Gap-fill on gossip**. Blocks with `b.Index > tip+1` trigger `SyncFromPeerFull` to the gossiping peer (rate-limited 1 per peer per minute). Nodes recover from brief outages without restart. ### API surface & security - **Rate limiter** (`node/api_guards.go`). Per-IP token bucket on `/api/tx` and `/v2/chain/transactions`: 10 tx/s, burst 20. - **Request-size cap**. `/api/tx` body ≤ 64 KiB. - **Timestamp validation**. ±1 h window on submit, refuses clock-skewed or replayed txs. - **Humanised errors in client**. `humanizeTxError` translates 429 / 400+timestamp / 400+signature / network-failure into Russian user- facing text. ### Observability & ops - **Prometheus `/metrics`**. Zero-dep in-tree implementation (`node/metrics.go`) with counters (blocks, txs, submit accepted/rejected), gauges (ws connections, peer count, max missed blocks), histogram (block commit seconds). - **Load test**. `cmd/loadtest` — N concurrent WS clients with auth + scoped subs + TRANSFER at rate. Validates chain advances, reject rate, ws-drop count. Smoke at 20 clients × 15 s → 136 accepted / 0 rejected. - **Structured logging**. `--log-format=text|json` flag. JSON mode routes both `slog.*` and legacy `log.Printf` through one JSON handler for Loki/ELK ingestion. - **Observer mode**. `--observer` (env `DCHAIN_OBSERVER`) disables PBFT producer + heartbeat + auto-relay-register; node still gossips and serves HTTP/WS. For horizontally-scaling read-only API frontends. ### Deployment - **`deploy/single/`** — one-node production bundle: - Same `Dockerfile.slim` as the cluster variant. - Compose stack: 1 node + Caddy + optional Prometheus/Grafana. - Supports three operator-chosen access modes: - Public (no token) — anyone can read + submit. - Public reads, token-gated writes (`DCHAIN_API_TOKEN` set) — reads stay open, submit tx requires `Authorization: Bearer`. - Fully private (`DCHAIN_API_TOKEN` + `DCHAIN_API_PRIVATE`) — every endpoint requires the token. - Runbook covers three scenarios: genesis node, joiner, private. - **`deploy/prod/`** — 3-validator cluster for federations/consortiums. - **Access-token middleware** in `node/api_guards.go`: - `withWriteTokenGuard` gates POST /api/tx and WS submit_tx. - `withReadTokenGuard` gates reads when `--api-private` is set. - WS upgrade applies the same check; `submit_tx` ops on a non-authenticated connection are rejected with `submit_ack` rejected. - **All CLI flags accept `DCHAIN_*` env fallbacks** for Docker-driven configuration, including the new `DCHAIN_API_TOKEN` / `DCHAIN_API_PRIVATE`. ### Client (React Native / Expo) - WebSocket module `lib/ws.ts` with reconnect, auto-resubscribe, auto-auth on reconnect. - `useBalance`, `useContacts`, `useMessages` — all push-based with HTTP polling fallback after 15 s disconnect. - `useWellKnownContracts` — auto-syncs `settings.contractId` with node's canonical registry. - Safe-area-aware layout throughout. Tab bar no longer hides under home indicator on iPhone. - Username purchase UI with live validation (min 4, first letter, charset). - Transaction detail sheet with system-tx handling (BLOCK_REWARD shows "Сеть" as counterpart, not validator's self-pay). --- ## Deliberately deferred - **Split `blockchain/chain.go`** into `state/`, `applytx/`, `mempool/`, `index/`, `events/` subpackages. A ~2.5k-line single-file refactor is high risk; to be attempted after the chain has been running in prod long enough that regressions there would be caught fast. - **Full `p2p/` rewrite with typed event channel.** The libp2p integration works; event-bus was added at the node layer instead (see `node/events.go`). - **Full mempool admission pricing** (gas-priced priority queues). Current fair round-robin works within spam-proofing needs. --- ## Compatibility notes - BadgerDB tuning is compatible with databases created by previous versions; the first run reclaims old value-log space via `CompactNow()`. - `AddValidatorPayload` / `RemoveValidatorPayload` gained a `cosigs` field; older payloads without it still parse (default empty), but will fail the ⌈2/3⌉ threshold on chains with >1 validator. - `BLOCK_REWARD` transactions changed from `From=validator` to `From=""`. Old indexed records keep their previous `From`; new ones use the new shape. Explorer/client handle both. - Registration fee for usernames moved from internal `ctx.Debit` to `tx.Amount`. The WASM username_registry is superseded by `native:username_registry`; well-known endpoint returns the native version as canonical.