Files
dchain/docs/contracts/username_registry.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

5.7 KiB
Raw Blame History

username_registry

Привязка читаемых @username к адресам (Ed25519 pubkey). Forward (name → addr) и reverse (addr → name) lookup, передача ownership, освобождение имени.

Реализация: native Go (blockchain/native_username.go). Работает без WASM VM — нулевая латентность, не может повесить AddBlock. Старая WASM-версия заменена; клиенты получают канонический ID через /api/well-known-contracts.

Ключевые свойства

Contract ID native:username_registry
Version 2.1.0-native
Регистрация Flat fee 10 000 µT (0.01 T), burn — никому не идёт
Ограничения имени 432 символа, a-z 0-9 _ -, первый символ — буква
Зарезервированные system, admin, root, dchain, null, none
Один адрес — одно имя Чтобы сменить, нужно release + register

Комиссия 10 000 µT выбрана как баланс: достаточно дёшево для реальных пользователей, достаточно дорого чтобы один ID-squatter не забил тысячу имён из скучающего бота.

Оплата

Плата передаётся в tx.Amount (видна в истории транзакций), контракт проверяет её точное значение и вычитает из баланса отправителя. Не направляется никуда — токены сгорают.

Дополнительно платится tx.Fee = 1 000 µT за саму транзакцию — это network fee валидатору, стандартный MinFee для любой tx.

Итого: register(name) стоит 11 000 µT ≈ 0.011 T.

Методы

register(name) — payable 10000

Зарегистрировать имя для tx.From.

Проверки (в порядке):

  1. name валиден (длина, символы, не reserved)
  2. tx.Amount == 10 000 (ошибка register requires tx.amount = 10000 µT)
  3. Имя не занято
  4. tx.From не владеет другим именем
  5. Баланс отправителя достаточен для amount + fee + gas

Успех:

  • Списывает 10 000 µT с баланса (burn)
  • cstate[name:<name>] = tx.From
  • cstate[addr:<tx.From>] = name
  • Лог registered: <name> → <pubkey>

CLI-пример:

client call-contract \
  --key my.json \
  --contract native:username_registry \
  --method register \
  --args '["alice"]' \
  --amount 10000 \
  --node http://localhost:8081

Клиент-приложение делает это автоматически через Settings → «Купить никнейм».

resolve(name) — free

Прочитать владельца имени.

Логирует owner: <pubkey> или not found: <name>. Клиент в HTTP-API обычно использует прямое чтение state:

GET /api/contracts/native:username_registry/state/name:alice
→ { value_hex: "<hex of owner pubkey ASCII>" }

lookup(address) — free

Обратный lookup. Логирует name: <name> или no name: <address>. Клиент использует GET .../state/addr:<pubkey>.

transfer(name, new_owner) — free

Передать name другому адресу. Только текущий владелец может вызвать. Новый владелец не должен уже иметь имя.

release(name) — free

Удалить привязку. Только текущий владелец. Освобождает name и addr:<caller> для будущих регистраций.

State layout

Все ключи записываются в общий namespace cstate:native:username_registry::

Key Value
name:<name> Hex pubkey владельца (64 символа)
addr:<pubkey> ASCII-строка с именем

Значения хранятся как байты; HTTP endpoint /api/contracts/:id/state/:key возвращает их в value_hex, клиент делает hex → UTF-8 перед показом.

Клиентская интеграция

  • useWellKnownContracts хук авто-синхронизирует settings.contractId = native:username_registry
  • resolveUsername(contractId, name) и reverseResolve(contractId, addr) в client-app/lib/api.ts делают HTTP-запрос + hex-decode
  • Settings экран покупает никнейм через buildCallContractTx({amount: 10_000, ...}) + автоматический reverseResolve polling после submit для показа @name в профиле за ~1 блок

Отличия от предыдущей WASM-версии

WASM v1 Native v2
Fee 10^(7-len), tiered Flat 10 000 µT
Fee destination Contract treasury Burn
Min length 1 4
Payment point Debited inside contract, invisible in tx tx.Amount, visible in history
Latency ~10 ms (wazero startup) ~50 µs (direct Go call)
VM hang risk Да (требует timeout) Нет

Зарегистрированные в старой WASM-версии имена не мигрируются автоматически — операторам нужно пере-зарегистрировать после reset chain (см. CHANGELOG.md «Compatibility notes»).