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
7.4 KiB
escrow
Двусторонний trustless escrow. Buyer блокирует средства в contract treasury. Seller выполняет условие. Buyer подтверждает или открывает спор. При споре admin-арбитр решает исход.
Жизненный цикл
buyer seller admin
│ │ │
│─ create ─────▶│ │ treasury ← amount (locked)
│ (seller, │ │ status: active
│ amount) │ │
│ │ │
│ [seller delivered] │
│ │ │
│─ release ────▶│ │ treasury → seller
│ │ │ status: released
OR:
│─ dispute ────▶│ │ status: disputed
│ │─ dispute ────▶│ (either party can)
│ │ │
│ │ │─ resolve(winner=buyer) ──▶
│ │ │ treasury → buyer
│ │ │ status: refunded
│ │ │
│ │ │─ resolve(winner=seller) ──▶
│ │ │ treasury → seller
│ │ │ status: released
OR:
│ │─ refund ─────▶│ treasury → buyer (voluntary)
│ │ │ status: refunded
Статусы: active → released / refunded / disputed
Методы
init
Установить caller как admin (арбитр споров).
Аргументы: нет
Вызывается один раз после деплоя (deploy-скрипт делает автоматически).
client call-contract --method init \
--contract $ESC_ID --key /keys/node1.json \
--gas 5000 --node http://node1:8080
create
Buyer создаёт escrow и блокирует средства.
Аргументы:
| # | Имя | Тип | Описание |
|---|---|---|---|
| 0 | id |
string | Уникальный ID эскроу (задаёт пользователь) |
| 1 | seller |
string | Pubkey продавца (hex) |
| 2 | amount |
uint64 | Сумма в µT |
Поведение:
- Переводит
amountс caller (buyer) → treasury - Сохраняет buyer, seller, amount, status=active
- Лог:
created: <id>
Ограничения:
- ID должен быть уникальным — если
cstate[e:<id>:b]уже есть, tx отклоняется
client call-contract --method create \
--arg "deal-001" \
--arg <SELLER_PUBKEY> \
--arg64 10000000 \
--contract $ESC_ID --key /tmp/buyer.json \
--gas 30000 --node http://node1:8080
release
Buyer подтверждает получение и освобождает средства seller'у.
Аргументы:
| # | Имя | Тип |
|---|---|---|
| 0 | id |
string |
Права: только buyer.
Статус: должен быть active.
Поведение:
- Переводит
amountс treasury → seller - Статус → released
- Лог:
released: <id>
client call-contract --method release --arg "deal-001" \
--contract $ESC_ID --key /tmp/buyer.json \
--gas 20000 --node http://node1:8080
refund
Seller добровольно возвращает деньги buyer'у.
Аргументы:
| # | Имя | Тип |
|---|---|---|
| 0 | id |
string |
Права: только seller.
Статус: должен быть active.
Поведение:
- Переводит
amountс treasury → buyer - Статус → refunded
- Лог:
refunded: <id>
client call-contract --method refund --arg "deal-001" \
--contract $ESC_ID --key /tmp/seller.json \
--gas 20000 --node http://node1:8080
dispute
Открыть спор. Может вызвать buyer или seller.
Аргументы:
| # | Имя | Тип |
|---|---|---|
| 0 | id |
string |
Статус: должен быть active.
Поведение:
- Статус → disputed
- Лог:
disputed: <id> - Средства остаются заблокированы в treasury
client call-contract --method dispute --arg "deal-001" \
--contract $ESC_ID --key /tmp/buyer.json \
--gas 10000 --node http://node1:8080
resolve
Admin разрешает спор.
Аргументы:
| # | Имя | Тип | Значения |
|---|---|---|---|
| 0 | id |
string | ID эскроу |
| 1 | winner |
string | buyer или seller |
Права: только admin.
Статус: должен быть disputed.
Поведение:
winner=buyer→ treasury → buyer, статус → refundedwinner=seller→ treasury → seller, статус → released- Лог:
resolved: <id>
# Admin решает в пользу buyer
client call-contract --method resolve \
--arg "deal-001" --arg buyer \
--contract $ESC_ID --key /keys/node1.json \
--gas 20000 --node http://node1:8080
# Admin решает в пользу seller
client call-contract --method resolve \
--arg "deal-001" --arg seller \
--contract $ESC_ID --key /keys/node1.json \
--gas 20000 --node http://node1:8080
info
Запросить состояние эскроу.
Аргументы:
| # | Имя | Тип |
|---|---|---|
| 0 | id |
string |
Логи:
buyer: <pubkey>
seller: <pubkey>
amount: <µT>
status: active|released|refunded|disputed
client call-contract --method info --arg "deal-001" \
--contract $ESC_ID --key /keys/node1.json \
--gas 5000 --node http://node1:8080
State Layout
cstate:<contractID>:admin → admin pubkey
cstate:<contractID>:e:<id>:b → buyer pubkey
cstate:<contractID>:e:<id>:s → seller pubkey
cstate:<contractID>:e:<id>:a → amount (uint64 big-endian)
cstate:<contractID>:e:<id>:x → status byte ('a'=active, 'd'=disputed, 'r'=released, 'f'=refunded)
Полный сценарий с dispute
# Параметры
BUYER_KEY=/tmp/buyer.json
SELLER_KEY=/tmp/seller.json
ADMIN_KEY=/keys/node1.json
ID="escrow-001"
# 1. Buyer создаёт эскроу на 5 T
docker exec node1 client call-contract \
--key $BUYER_KEY --contract $ESC_ID \
--method create \
--arg $ID --arg $SELLER_PUB --arg64 5000000 \
--gas 30000 --node http://node1:8080
# 2. Проверить статус
docker exec node1 client call-contract \
--key $BUYER_KEY --contract $ESC_ID \
--method info --arg $ID \
--gas 5000 --node http://node1:8080
# status: active
# 3. Buyer не доволен — открывает спор
docker exec node1 client call-contract \
--key $BUYER_KEY --contract $ESC_ID \
--method dispute --arg $ID \
--gas 10000 --node http://node1:8080
# 4. Admin рассматривает дело и решает в пользу seller
docker exec node1 client call-contract \
--key $ADMIN_KEY --contract $ESC_ID \
--method resolve --arg $ID --arg seller \
--gas 20000 --node http://node1:8080
# Лог: resolved: escrow-001
# Seller получает 5 T