Aller au contenu principal

Architecture du stockage

Le réseau Savitri utilise RocksDB comme moteur de stockage principal, avec des familles de colonnes pour l'isolation des données et des schémas d'accès efficaces.

Familles de colonnes

Famille de colonnesCléValeurObjectif
CF_BLOCKShauteur (u64 LE)Bloc (bincode)Stockage des blocs
CF_TRANSACTIONStx_hash (32 octets)Transaction (bincode)Recherche de transactions
CF_ACCOUNTSadresse (32 octets)Compte (24 octets)Solde + nonce
CF_METADATAclé textevariableTête de chaîne, configuration
CF_RECEIPTStx_hashReçu (bincode)Reçus de transactions
CF_CONTRACTSadresseContractInfoÉtat des contrats intelligents
CF_GOVERNANCEproposal_idProposition (bincode)Propositions de gouvernance
CF_ORACLEfeed_idOracleDataFlux d'oracles
CF_BONDSadresseMontant du cautionnementCautionnements des validateurs
CF_VOTE_TOKENSadresseSolde VoteTokenTokens de vote de gouvernance
CF_TREASURYcléÉtat du trésorTrésor du réseau
CF_VESTINGschedule_idVestingScheduleAcquisition progressive de tokens
CF_REWARD_COINSadresseSolde de récompensesRécompenses des nœuds
CF_FEE_METRICScléDonnées de fraisSuivi des frais
CF_SUPPLY_METRICScléDonnées d'offreOffre de tokens
CF_ACTIVE_NODESnode_idActivitéDisponibilité des nœuds
CF_MONOLITHSmonolith_idMonolitheCompression de blocs
CF_FLcléDonnées FLApprentissage fédéré
CF_POUnode_idScore PoUScores de consensus

Encodage des comptes

Les comptes utilisent un encodage compact en format fixe de 24 octets :

Octets 0-15  : solde (u128, little-endian)
Octets 16-23 : nonce (u64, little-endian)

Rétrocompatible : l'ancien format de 16 octets (solde uniquement, nonce=0) est toujours pris en charge.

Les comptes vides (solde=0, nonce=0) ne sont jamais persistés pour économiser de l'espace de stockage.

Racine d'état

La racine d'état est calculée via un instantané lexicographique de la base de données :

seed  = H("STATEv1-LE")
leaf = H("STATE" || key || value) pour chaque paire clé-valeur
root = rolling_accumulate(seed, leaf_1, leaf_2, ..., leaf_n)

Les clés sont itérées dans l'ordre lexicographique pour assurer le déterminisme.

Trait de stockage

Tous les backends de stockage implémentent le 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>)>>;
// ... opérations par lot, itération, etc.
}

Désérialisation sécurisée

Toute désérialisation bincode utilise une limite de taille maximale pour prévenir l'épuisement de la mémoire :

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

Mise en cache

Couche de cache LRU pour les données fréquemment consultées :

  • Cache des comptes : réduit les lectures RocksDB pour les vérifications de solde/nonce
  • Cache de stockage de contrats : met en cache les résultats SLOAD dans l'exécution de contrats
  • Cache de scores : cache LRU pour la notation des transactions du mempool (évite les recalculs)

Configuration RocksDB

ParamètreDéveloppementProduction
Taille du cache256 Mo1024 Mo
Tampon d'écriture16 Mo64 Mo
Nombre max. de fichiers ouverts1001000
Intervalle de synchronisation5s30s
CompressionDésactivéeActivée

Opérations par lot

Les écritures atomiques par lot assurent la cohérence :

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()?;

Système d'acquisition progressive

Les calendriers d'acquisition progressive de tokens prennent en charge trois types :

TypeComportement
LinearTokens libérés linéairement sur la durée
CliffAucun token avant la période de blocage, puis linéaire
StagedMode de compatibilité genèse

Indicateurs de fonctionnalité

IndicateurDescription
rocksdbBackend RocksDB (par défaut)
memoryBackend en mémoire (tests)
prometheusExport de métriques Prometheus
tempfileStockage temporaire pour les tests