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
275 lines
8.0 KiB
Markdown
275 lines
8.0 KiB
Markdown
# Host Functions
|
||
|
||
Полный справочник 14 host-функций, которые DChain экспортирует в WASM-контракты через модуль `env`.
|
||
|
||
Все функции регистрируются в `vm/host.go`. Контракт импортирует их через `//go:wasmimport env <name>` (TinyGo) или напрямую в секции `imports` WASM-модуля.
|
||
|
||
---
|
||
|
||
## Аргументы
|
||
|
||
### `get_args`
|
||
|
||
```
|
||
get_args(dstPtr i32, dstLen i32) → written i32
|
||
```
|
||
|
||
Читает весь JSON-массив аргументов транзакции в буфер `[dstPtr, dstPtr+dstLen)`.
|
||
Возвращает количество записанных байт (0 если аргументов нет).
|
||
|
||
---
|
||
|
||
### `get_arg_str`
|
||
|
||
```
|
||
get_arg_str(idx i32, dstPtr i32, dstLen i32) → written i32
|
||
```
|
||
|
||
Читает аргумент с индексом `idx` как строку (без кавычек JSON).
|
||
`dstLen` — максимальная длина буфера.
|
||
Возвращает 0 если аргумент не существует или тип не строка.
|
||
|
||
**SDK:** `dc.ArgStr(idx, maxLen)`
|
||
|
||
---
|
||
|
||
### `get_arg_u64`
|
||
|
||
```
|
||
get_arg_u64(idx i32) → val i64
|
||
```
|
||
|
||
Читает аргумент с индексом `idx` как беззнаковое 64-битное число.
|
||
Возвращает 0 если индекс вне диапазона или тип не число.
|
||
|
||
**SDK:** `dc.ArgU64(idx)`
|
||
|
||
---
|
||
|
||
## State
|
||
|
||
### `get_state_len`
|
||
|
||
```
|
||
get_state_len(keyPtr i32, keyLen i32) → valLen i32
|
||
```
|
||
|
||
Возвращает размер значения по ключу (0 если ключ не найден).
|
||
Используется перед `get_state` для выделения буфера нужного размера.
|
||
|
||
---
|
||
|
||
### `get_state`
|
||
|
||
```
|
||
get_state(keyPtr i32, keyLen i32, dstPtr i32, dstLen i32) → written i32
|
||
```
|
||
|
||
Читает `min(len(value), dstLen)` байт по ключу в буфер.
|
||
Возвращает фактически записанное количество байт.
|
||
|
||
**SDK:** `dc.GetState(key)` (выделяет буфер автоматически через `get_state_len`)
|
||
|
||
---
|
||
|
||
### `set_state`
|
||
|
||
```
|
||
set_state(keyPtr i32, keyLen i32, valPtr i32, valLen i32)
|
||
```
|
||
|
||
Записывает значение по ключу. Если `valLen == 0` — удаляет ключ.
|
||
|
||
**SDK:** `dc.SetState(key, value)`, `dc.SetStateStr(key, s)`, `dc.PutU64(key, v)`
|
||
|
||
---
|
||
|
||
### `put_u64`
|
||
|
||
```
|
||
put_u64(keyPtr i32, keyLen i32, val i64)
|
||
```
|
||
|
||
Записывает `val` как 8 байт big-endian. Эквивалентно `set_state` с 8-байтным big-endian значением, но компактнее в вызове.
|
||
|
||
**SDK:** `dc.PutU64(key, v)`
|
||
|
||
---
|
||
|
||
### `get_u64`
|
||
|
||
```
|
||
get_u64(keyPtr i32, keyLen i32) → val i64
|
||
```
|
||
|
||
Читает 8 байт big-endian по ключу. Возвращает 0 если ключ не найден.
|
||
|
||
**SDK:** `dc.GetU64(key)`
|
||
|
||
---
|
||
|
||
## Идентификация
|
||
|
||
### `get_caller`
|
||
|
||
```
|
||
get_caller(bufPtr i32, bufLen i32) → written i32
|
||
```
|
||
|
||
Записывает hex-pubkey вызывающего аккаунта (64 символа ASCII).
|
||
Если `bufLen < 64`, записывает частично.
|
||
|
||
**SDK:** `dc.Caller()`
|
||
|
||
---
|
||
|
||
### `get_block_height`
|
||
|
||
```
|
||
get_block_height() → height i64
|
||
```
|
||
|
||
Возвращает высоту текущего блока (в котором исполняется транзакция).
|
||
|
||
**SDK:** `dc.BlockHeight()`
|
||
|
||
---
|
||
|
||
### `get_contract_treasury`
|
||
|
||
```
|
||
get_contract_treasury(bufPtr i32, bufLen i32) → written i32
|
||
```
|
||
|
||
Записывает hex-pubkey treasury контракта (64 символа).
|
||
Treasury — специальный счёт, привязанный к контракту. Контракт может переводить с treasury как `from` без ограничений.
|
||
|
||
**SDK:** `dc.Treasury()`
|
||
|
||
---
|
||
|
||
## Токены
|
||
|
||
### `get_balance`
|
||
|
||
```
|
||
get_balance(pubPtr i32, pubLen i32) → balance i64
|
||
```
|
||
|
||
Возвращает баланс адреса в µT (микро-токены).
|
||
|
||
**SDK:** `dc.Balance(pubKeyHex)`
|
||
|
||
---
|
||
|
||
### `transfer`
|
||
|
||
```
|
||
transfer(fromPtr i32, fromLen i32, toPtr i32, toLen i32, amount i64) → errCode i32
|
||
```
|
||
|
||
Переводит `amount` µT с `from` на `to`.
|
||
Возвращает 0 при успехе, 1 при ошибке (недостаточно средств, неверный адрес).
|
||
|
||
**Ограничения:**
|
||
- `from` должен быть либо `dc.Caller()`, либо `dc.Treasury()`.
|
||
- Контракт не может тратить чужие деньги (только caller'а или свой treasury).
|
||
|
||
**SDK:** `dc.Transfer(from, to, amount) bool`
|
||
|
||
---
|
||
|
||
## Межконтрактные вызовы
|
||
|
||
### `call_contract`
|
||
|
||
```
|
||
call_contract(cidPtr i32, cidLen i32, mthPtr i32, mthLen i32, argPtr i32, argLen i32) → errCode i32
|
||
```
|
||
|
||
Вызывает метод другого контракта.
|
||
|
||
| Параметр | Тип | Описание |
|
||
|---------|-----|---------|
|
||
| `cidPtr/cidLen` | i32 | hex-ID целевого контракта (16 символов) |
|
||
| `mthPtr/mthLen` | i32 | имя метода |
|
||
| `argPtr/argLen` | i32 | JSON-массив аргументов |
|
||
|
||
**Возврат:** 0 = успех, 1 = ошибка (превышена глубина, контракт не найден, и т.д.)
|
||
|
||
**Gas:** подвызов получает `gc.Remaining()` от родительского счётчика. Потраченный gas вычитается из родителя.
|
||
|
||
**State:** все вызовы в цепочке разделяют одну `badger.Txn`. Если подвызов не падает, его изменения видны родителю.
|
||
|
||
**Подробнее:** [Межконтрактные вызовы](inter-contract.md)
|
||
|
||
**SDK:** `dc.CallContract(contractID, method, argsJSON) bool`
|
||
|
||
---
|
||
|
||
## Логирование
|
||
|
||
### `log`
|
||
|
||
```
|
||
log(msgPtr i32, msgLen i32)
|
||
```
|
||
|
||
Записывает строку в лог контракта. Логи привязаны к транзакции и видны в Explorer → вкладка Logs.
|
||
|
||
`fmt.Println` и `log.Printf` через WASI stdout **не** попадают в блокчейн-логи. Используйте только `log`.
|
||
|
||
**SDK:** `dc.Log(msg)`
|
||
|
||
---
|
||
|
||
## Gas
|
||
|
||
### `gas_tick`
|
||
|
||
```
|
||
gas_tick()
|
||
```
|
||
|
||
Вызывается автоматически при каждой итерации цикла в бинарных WASM-контрактах (инструментация вручную). Списывает 1 unit gas.
|
||
|
||
Для TinyGo-контрактов TinyGo генерирует собственную инструментацию.
|
||
|
||
---
|
||
|
||
## Таблица функций
|
||
|
||
| # | Имя | Сигнатура | SDK |
|
||
|---|-----|----------|-----|
|
||
| 1 | `get_args` | `(i32,i32)→i32` | — |
|
||
| 2 | `get_arg_str` | `(i32,i32,i32)→i32` | `ArgStr` |
|
||
| 3 | `get_arg_u64` | `(i32)→i64` | `ArgU64` |
|
||
| 4 | `get_state_len` | `(i32,i32)→i32` | внутри `GetState` |
|
||
| 5 | `get_state` | `(i32,i32,i32,i32)→i32` | `GetState` |
|
||
| 6 | `set_state` | `(i32,i32,i32,i32)` | `SetState` |
|
||
| 7 | `put_u64` | `(i32,i32,i64)` | `PutU64` |
|
||
| 8 | `get_u64` | `(i32,i32)→i64` | `GetU64` |
|
||
| 9 | `get_caller` | `(i32,i32)→i32` | `Caller` |
|
||
| 10 | `get_block_height` | `()→i64` | `BlockHeight` |
|
||
| 11 | `get_contract_treasury` | `(i32,i32)→i32` | `Treasury` |
|
||
| 12 | `get_balance` | `(i32,i32)→i64` | `Balance` |
|
||
| 13 | `transfer` | `(i32,i32,i32,i32,i64)→i32` | `Transfer` |
|
||
| 14 | `call_contract` | `(i32,i32,i32,i32,i32,i32)→i32` | `CallContract` |
|
||
| 15 | `log` | `(i32,i32)` | `Log` |
|
||
| 16 | `gas_tick` | `()` | — |
|
||
|
||
---
|
||
|
||
## Паттерн прямого импорта (без SDK)
|
||
|
||
Если вы пишете бинарный WASM вручную (без TinyGo), функции импортируются в секции `imports`:
|
||
|
||
```
|
||
(import "env" "get_state_len" (func (param i32 i32) (result i32)))
|
||
(import "env" "get_state" (func (param i32 i32 i32 i32) (result i32)))
|
||
(import "env" "set_state" (func (param i32 i32 i32 i32)))
|
||
...
|
||
```
|
||
|
||
Подробнее: [Бинарный WASM](binary-wasm.md)
|