Files
dchain/docs/development/gas-model.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

194 lines
6.2 KiB
Markdown
Raw Permalink 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.

# Gas и Treasury
## Gas модель
Каждый вызов контракта (`CALL_CONTRACT` транзакция) тратит gas. Gas конвертируется в µT и списывается со счёта отправителя.
### Формула
```
fee = gas_used × gas_price
```
| Параметр | Значение | Откуда |
|---------|---------|-------|
| `gas_used` | ≤ `--gas` лимит | считается VM |
| `gas_price` | 1 µT/gas по умолчанию | governance или константа |
### Лимит gas
Задаётся в транзакции флагом `--gas`:
```bash
client call-contract --method increment \
--gas 5000 \
--contract $CONTRACT_ID --key key.json --node http://localhost:8081
```
Если VM израсходует весь лимит до конца исполнения — транзакция откатывается, gas не возвращается.
### Что стоит gas
| Операция | Стоимость |
|---------|---------|
| Итерация цикла (`gas_tick`) | 1 unit |
| Внешний вызов (`call_contract`) | gas подвызова |
| Прочие инструкции | 0 (не инструментированы) |
> TinyGo автоматически вставляет `gas_tick` в циклы. Бинарные WASM-контракты вызывают `gas_tick` вручную.
### Межконтрактный gas
При вызове `dc.CallContract(...)`, подвызов получает budget = `Remaining()` родителя.
После возврата, `gasUsed` подвызова списывается с родительского счётчика.
```
Родитель: limit=5000, used=200
→ подвызов budget = 4800
→ подвызов использовал 300
Родитель: used = 200 + 300 = 500
```
## Treasury
Каждый контракт имеет **treasury** — специальный баланс, привязанный к контракту.
### Получить адрес treasury
```go
treasury := dc.Treasury() // hex pubkey, 64 символа
```
### Переводы через treasury
Treasury используется как промежуточный эскроу:
```go
// Принять деньги от caller → treasury
dc.Transfer(dc.Caller(), dc.Treasury(), amount)
// Отправить деньги из treasury → получателю
dc.Transfer(dc.Treasury(), recipient, amount)
```
**Ограничение:** в `dc.Transfer(from, ...)`, `from` может быть только:
1. `dc.Caller()` — списать со счёта вызывающего
2. `dc.Treasury()` — списать с treasury контракта
Контракт **не может** списывать деньги с произвольных адресов.
### Проверить баланс treasury
```go
treasuryBal := dc.Balance(dc.Treasury())
```
### Паттерны использования treasury
**1. Fee collector:**
```go
const fee = 1000 // µT
dc.Transfer(dc.Caller(), dc.Treasury(), fee)
// Деньги остаются в treasury навсегда (или до явного вывода)
```
**2. Эскроу (lock → release):**
```go
// lock: buyer → treasury
dc.Transfer(buyer, dc.Treasury(), amount)
// release: treasury → seller
dc.Transfer(dc.Treasury(), seller, amount)
// refund: treasury → buyer
dc.Transfer(dc.Treasury(), buyer, amount)
```
**3. Prize pool (аукцион):**
```go
// Принять ставку
dc.Transfer(bidder, dc.Treasury(), bid)
// Возврат предыдущей ставки
dc.Transfer(dc.Treasury(), prevBidder, prevBid)
// Финал: перевод победителю
dc.Transfer(dc.Treasury(), seller, topBid)
```
## Governance и динамический gas_price
По умолчанию `gas_price = 1 µT/gas`. Это значение можно изменить через governance-контракт.
### Как нода читает gas_price
```go
// blockchain/chain.go
func (c *Chain) GetEffectiveGasPrice() uint64 {
val, ok := c.GetGovParam("gas_price")
if !ok { return GasPrice } // константа по умолчанию
price, err := strconv.ParseUint(val, 10, 64)
if err != nil { return GasPrice }
return price
}
```
`GetGovParam` читает `cstate:<govID>:param:gas_price` напрямую из BadgerDB без VM-вызова.
### Изменить gas_price через governance
```bash
# Предложить новое значение (5 µT/gas)
client call-contract --method propose \
--arg gas_price --arg 5 \
--contract $GOV_ID --key /keys/node1.json \
--gas 10000 --node http://node1:8080
# Admin утверждает
client call-contract --method approve \
--arg gas_price \
--contract $GOV_ID --key /keys/node1.json \
--gas 10000 --node http://node1:8080
```
После approve все последующие `CALL_CONTRACT` транзакции будут использовать новую цену.
### Проверить текущий gas_price
```bash
# Через контракт
client call-contract --method get \
--arg gas_price \
--contract $GOV_ID --key key.json \
--gas 3000 --node http://localhost:8081
# Через REST (без транзакции)
curl http://localhost:8081/api/contracts/$GOV_ID/state/param:gas_price
```
## Константы
```go
// blockchain/chain.go
const (
GasPrice = uint64(1) // µT за 1 gas unit (default)
)
// vm/host.go
const (
maxContractCallDepth = 8
)
```
## Рекомендации по выбору --gas
| Операция | Рекомендуемый gas |
|---------|-----------------|
| Простое чтение/запись state | 3 000 |
| Регистрация / короткий метод | 5 000 |
| Метод с несколькими state операциями | 10 000 |
| Создание эскроу/аукциона | 20 000 30 000 |
| Метод с межконтрактным вызовом | 30 000 50 000 |
Gas, который не был потрачён, **не возвращается**. Завышенный лимит безопасен, но лишних денег не списывается больше `gas_used × gas_price`.