Перейти к основному содержимому

Архитектура хранилища

Savitri Network использует RocksDB в качестве основного бэкенда хранилища со столбцовыми семействами для изоляции данных и эффективных паттернов доступа.

Столбцовые семейства

Столбцовое семействоКлючЗначениеНазначение
CF_BLOCKSвысота (u64 LE)Block (bincode)Хранение блоков
CF_TRANSACTIONStx_hash (32 байта)Transaction (bincode)Поиск транзакций
CF_ACCOUNTSадрес (32 байта)Account (24 байта)Баланс + nonce
CF_METADATAстроковый ключразныеГолова цепи, конфигурация
CF_RECEIPTStx_hashReceipt (bincode)Квитанции транзакций
CF_CONTRACTSадресContractInfoСостояние смарт-контракта
CF_GOVERNANCEproposal_idProposal (bincode)Предложения управления
CF_ORACLEfeed_idOracleDataПотоки оракулов
CF_BONDSадресBond amountЗалоги валидаторов
CF_VOTE_TOKENSадресVoteToken balanceТокены голосования управления
CF_TREASURYключTreasury stateКазначейство сети
CF_VESTINGschedule_idVestingScheduleВестинг токенов
CF_REWARD_COINSадресReward balanceВознаграждения нод
CF_FEE_METRICSключFee dataОтслеживание комиссий
CF_SUPPLY_METRICSключSupply dataОбъём токенов
CF_ACTIVE_NODESnode_idActivityАктивность нод
CF_MONOLITHSmonolith_idMonolithСжатие блоков
CF_FLключFL dataФедеративное обучение
CF_POUnode_idPoU scoreОценки консенсуса

Кодирование аккаунтов

Аккаунты используют компактное 24-байтовое кодирование фиксированной ширины:

Байты 0-15:  balance (u128, little-endian)
Байты 16-23: nonce (u64, little-endian)

Обратно совместимо: старый 16-байтовый формат (только balance, nonce=0) по-прежнему поддерживается.

Пустые аккаунты (balance=0, nonce=0) никогда не сохраняются для экономии места в хранилище.

Корень состояния

Корень состояния вычисляется через лексикографический снимок базы данных:

seed  = H("STATEv1-LE")
leaf = H("STATE" || key || value) для каждой пары ключ-значение
root = rolling_accumulate(seed, leaf_1, leaf_2, ..., leaf_n)

Ключи итерируются в лексикографическом порядке для детерминизма.

Трейт хранилища

Все бэкенды хранилища реализуют StorageTrait:

pub trait StorageTrait: Send + Sync {
fn get_cf(&self, cf: &str, key: &[u8]) -> Result<Option<Vec<u8>>>;
fn put_cf(&self, cf: &str, key: &[u8], value: &[u8]) -> Result<()>;
fn delete_cf(&self, cf: &str, key: &[u8]) -> Result<()>;
fn get_cf_prefix(&self, cf: &str, prefix: &[u8]) -> Result<Vec<(Vec<u8>, Vec<u8>)>>;
// ... пакетные операции, итерация и т.д.
}

Безопасная десериализация

Вся десериализация bincode использует максимальное ограничение размера для предотвращения исчерпания памяти:

const MAX_BINCODE_SIZE: u64 = 16 * 1024 * 1024; // 16MB

Кеширование

Уровень LRU-кеша для часто запрашиваемых данных:

  • Кеш аккаунтов: уменьшает количество чтений RocksDB при проверке баланса/nonce
  • Кеш хранилища контрактов: кеширует результаты SLOAD в пределах выполнения контракта
  • Кеш оценок: LRU-кеш для оценки транзакций в мемпуле (избегает повторного вычисления)

Конфигурация RocksDB

ПараметрРазработкаПродакшн
Размер кеша256 МБ1024 МБ
Буфер записи16 МБ64 МБ
Макс. открытых файлов1001000
Интервал синхронизации30с
СжатиеОтключеноВключено

Пакетные операции

Атомарные пакетные записи обеспечивают согласованность:

let mut batch = storage.batch();
batch.put_cf(CF_ACCOUNTS, &addr, &account.encode());
batch.put_cf(CF_TRANSACTIONS, &tx_hash, &tx_bytes);
batch.put_cf(CF_BLOCKS, &height_key, &block_bytes);
batch.commit()?;

Система вестинга

Расписания вестинга токенов поддерживают три типа:

ТипПоведение
LinearТокены высвобождаются линейно на протяжении периода
CliffНет токенов до периода клиффа, затем линейно
StagedРежим совместимости с генезисом

Флаги функций

ФлагОписание
rocksdbБэкенд RocksDB (по умолчанию)
memoryБэкенд в памяти (тестирование)
prometheusЭкспорт метрик Prometheus
tempfileВременное хранилище для тестов