Files
dchain/CHANGELOG.md
vsecoder 7e7393e4f8 chore: initial commit for v0.0.1
DChain single-node blockchain + React Native messenger client.

Core:
- PBFT consensus with multi-sig validator admission + equivocation slashing
- BadgerDB + schema migration scaffold (CurrentSchemaVersion=0)
- libp2p gossipsub (tx/v1, blocks/v1, relay/v1, version/v1)
- Native Go contracts (username_registry) alongside WASM (wazero)
- WebSocket gateway with topic-based fanout + Ed25519-nonce auth
- Relay mailbox with NaCl envelope encryption (X25519 + Ed25519)
- Prometheus /metrics, per-IP rate limit, body-size cap

Deployment:
- Single-node compose (deploy/single/) with Caddy TLS + optional Prometheus
- 3-node dev compose (docker-compose.yml) with mocked internet topology
- 3-validator prod compose (deploy/prod/) for federation
- Auto-update from Gitea via /api/update-check + systemd timer
- Build-time version injection (ldflags → node --version)
- UI / Swagger toggle flags (DCHAIN_DISABLE_UI, DCHAIN_DISABLE_SWAGGER)

Client (client-app/):
- Expo / React Native / NativeWind
- E2E NaCl encryption, typing indicator, contact requests
- Auto-discovery of canonical contracts, chain_id aware, WS reconnect on node switch

Documentation:
- README.md, CHANGELOG.md, CONTEXT.md
- deploy/single/README.md with 6 operator scenarios
- deploy/UPDATE_STRATEGY.md with 4-layer forward-compat design
- docs/contracts/*.md per contract
2026-04-17 14:16:44 +03:00

182 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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:<block20d>:<seq04d>`). `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:<pub>`, `inbox:<x25519>`,
`contract_log`, `contract:<id>`, `typing:<x25519>`.
- **`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:<pub>` timestamp; `/api/relays` filters anything
older than 2 hours. Stale relays are delisted automatically.
### Node onboarding
- **`--join <url1,url2,…>`** — multi-seed bootstrap. Tries each URL in
order, persists the live list to `<db>/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.