Среда выполнения контрактов
Среда выполнения контрактов Savitri исполняет смарт-контракты в изолированной среде с измерением газа, изоляцией хранилища и генерацией событий.
Поток выполнения
Contract Call TX arrives
│
▼
BaseContract validation
│ check paused, owner, reserved slots
▼
Gas Meter initialization
│ gas_limit from TX fee
▼
ContractStorage setup
│ load contract state, init cache
▼
Function dispatch
│ match function_selector → handler
▼
Execution (with gas tracking)
│ SLOAD, SSTORE, events, calls
▼
Result
├── Success → commit storage, emit events
└── Failure → revert all changes
BaseContract
Все контракты расширяют BaseContract. Слоты 0–99 зарезервированы:
| Слот | Поле | Размер | Описание |
|---|---|---|---|
| 0 | owner | 32 байта | Адрес владельца контракта |
| 1 | version | u64 | Версия контракта |
| 2 | governance_hook | bool | Интеграция с управлением включена |
| 3 | fee_hook | bool | Пользовательская логика комиссий включена |
| 4 | paused | bool | Состояние паузы контракта |
| 5–99 | Зарезервировано | - | Для будущего использования |
Функции BaseContract
| Функция | Доступ | Описание |
|---|---|---|
owner() | Публичный | Получить владельца контракта |
transfer_ownership(new_owner) | Только владелец | Передать право собственности |
version() | Публичный | Получить версию контракта |
upgrade(new_version) | Только владелец | Обновить контракт |
pause() | Только владелец | Приостановить все операции |
unpause() | Только владелец | Возобновить операции |
Измерение газа
Стоимость газа
| Операция | Газ | Описание |
|---|---|---|
SLOAD | 100 | Чтение хранилища |
SSTORE (новое) | 20 000 | Запись в хранилище (пустой слот) |
SSTORE (обновление) | 5 000 | Запись в хранилище (существующий слот) |
CALL | 2 300 | Межконтрактный вызов |
CREATE | 32 000 | Развёртывание контракта |
TRANSFER | 300 | Перевод токена |
LOG | 375 | Генерация события (базовая) |
LOG_TOPIC | 375 | За каждую дополнительную тему |
LOG_DATA | 8 | За каждый байт данных события |
CALLDATA | 16 | За каждый байт данных вызова |
Пакетный учёт
Счётчик газа использует пакетный учёт (100 операций на пакет) для снижения накладных расходов. Газ фиксируется пакетами, а не за каждую операцию.
Лимит газа
Лимит газа вычисляется из комиссии транзакции:
gas_limit = tx.fee / gas_price
Если газ заканчивается во время выполнения, вся транзакция откатывается.
Хранилище контракта
Модель на основе слотов
Каждый контракт имеет независимое хранилище типа ключ-значение, где ключами являются номера слотов u64, а значениями — 32-байтовые массивы.
Вычисление слотов
Для маппингов слоты вычисляются с использованием Keccak256 для предотвращения коллизий:
// Simple value
slot = FIXED_SLOT_NUMBER
// Mapping (address → value)
slot = keccak256(address || base_slot)[0..8] as u64
// Nested mapping (address → address → value)
inner = keccak256(outer_key || base_slot)
slot = keccak256(inner_key || inner)[0..8] as u64
Дерево Меркла
Хранилище контракта поддерживает дерево Меркла для генерации доказательств состояния.
Система событий
Контракты генерируют события для внешних потребителей:
pub struct CustomEvent {
pub event_type: String, // e.g., "Transfer", "Approval"
pub topics: Vec<Vec<u8>>, // indexed fields
pub data: Vec<u8>, // non-indexed data
}
Стандартные события (из BaseContract):
OwnershipTransferred(old_owner, new_owner)ContractUpgraded(old_version, new_version)Paused(by)Unpaused(by)
Развёртывание контрактов
1. Create DeployTransaction (to = None, data = bytecode)
2. Assign contract address (derived from deployer + nonce)
3. Initialize BaseContract (set owner, version)
4. Run contract constructor (initialize function)
5. Store ContractInfo in CF_CONTRACTS
6. Emit ContractDeployed event
Вызовы контрактов
1. Parse function_selector from TX data
2. Load contract from CF_CONTRACTS
3. Check BaseContract state (not paused, etc.)
4. Initialize GasMeter with gas_limit
5. Execute function with ContractStorage
6. If success: commit storage changes, deduct gas
7. If failure: revert all changes
Интерпретатор EVM
Модуль evm_interpreter обеспечивает базовое выполнение байткода EVM для совместимости с контрактами Ethereum. Это позволяет развёртывать контракты, скомпилированные на Solidity, в сети Savitri.
Мониторинг памяти
Модуль memory_monitor отслеживает использование памяти во время выполнения для предотвращения DoS-атак:
- Лимиты памяти на контракт
- Отслеживание выделений памяти
- Автоматическое завершение при превышении лимитов
Параллельное выполнение
Модуль parallel обеспечивает параллельное выполнение контрактов для независимых транзакций:
- Анализ зависимостей между транзакциями
- Обнаружение конфликтов в слотах хранилища
- Параллельное выполнение неконфликтующих транзакций
- Последовательное выполнение в качестве запасного варианта для конфликтующих транзакций
Трассировка контрактов
Модуль tracing предоставляет трассировку выполнения для отладки:
- Пошаговый журнал выполнения
- Отслеживание чтения/записи хранилища
- Потребление газа на каждую операцию
- Журнал генерации событий