Passa al contenuto principale

Architettura dello Storage

Savitri Network utilizza RocksDB come backend di storage principale con column family per l'isolamento dei dati e pattern di accesso efficienti.

Column Family

Column FamilyChiaveValoreScopo
CF_BLOCKSaltezza (u64 LE)Blocco (bincode)Storage blocchi
CF_TRANSACTIONStx_hash (32 byte)Transazione (bincode)Ricerca transazioni
CF_ACCOUNTSindirizzo (32 byte)Account (24 byte)Saldo + nonce
CF_METADATAchiave stringavarioTesta della catena, configurazione
CF_RECEIPTStx_hashRicevuta (bincode)Ricevute delle transazioni
CF_CONTRACTSindirizzoContractInfoStato degli smart contract
CF_GOVERNANCEproposal_idProposta (bincode)Proposte di governance
CF_ORACLEfeed_idOracleDataFeed degli oracoli
CF_BONDSindirizzoImporto cauzioneCauzioni dei validatori
CF_VOTE_TOKENSindirizzoSaldo VoteTokenToken di voto per la governance
CF_TREASURYchiaveStato treasuryTreasury di rete
CF_VESTINGschedule_idVestingScheduleVesting dei token
CF_REWARD_COINSindirizzoSaldo ricompenseRicompense dei nodi
CF_FEE_METRICSchiaveDati commissioniMonitoraggio commissioni
CF_SUPPLY_METRICSchiaveDati offertaOfferta di token
CF_ACTIVE_NODESnode_idAttivitàStato attivo del nodo
CF_MONOLITHSmonolith_idMonolithCompressione blocchi
CF_FLchiaveDati FLApprendimento federato
CF_POUnode_idPunteggio PoUPunteggi di consenso

Codifica dell'Account

Gli account utilizzano una codifica compatta a larghezza fissa di 24 byte:

Byte 0-15:  saldo (u128, little-endian)
Byte 16-23: nonce (u64, little-endian)

Compatibilità con versioni precedenti: il vecchio formato a 16 byte (solo saldo, nonce=0) è ancora supportato.

Gli account vuoti (saldo=0, nonce=0) non vengono mai salvati per risparmiare spazio di archiviazione.

State Root

La state root viene calcolata tramite snapshot lessicografico del database:

seed  = H("STATEv1-LE")
leaf = H("STATE" || key || value) per ogni coppia chiave-valore
root = rolling_accumulate(seed, leaf_1, leaf_2, ..., leaf_n)

Le chiavi vengono iterate in ordine lessicografico per garantire il determinismo.

Trait dello Storage

Tutti i backend di storage implementano il 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>)>>;
// ... operazioni batch, iterazione, ecc.
}

Deserializzazione Sicura

Tutta la deserializzazione bincode utilizza un limite massimo di dimensione per prevenire l'esaurimento della memoria:

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

Caching

Livello di cache LRU per i dati a cui si accede frequentemente:

  • Cache account: riduce le letture RocksDB per le verifiche saldo/nonce
  • Cache storage contratti: memorizza i risultati SLOAD nell'esecuzione dei contratti
  • Cache punteggi: cache LRU per la valutazione TX nel mempool (evita il ricalcolo)

Configurazione RocksDB

ParametroSviluppoProduzione
Dimensione cache256 MB1024 MB
Buffer di scrittura16 MB64 MB
Max file aperti1001000
Intervallo sync5s30s
CompressioneDisabilitataAbilitata

Operazioni Batch

Le scritture batch atomiche garantiscono la coerenza:

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

Sistema di Vesting

I piani di vesting dei token supportano tre tipi:

TipoComportamento
LinearToken rilasciati linearmente nel tempo
CliffNessun token prima del periodo cliff, poi lineare
StagedModalità di compatibilità genesis

Flag di Funzionalità

FlagDescrizione
rocksdbBackend RocksDB (predefinito)
memoryBackend in memoria (test)
prometheusEsportazione metriche Prometheus
tempfileStorage temporaneo per i test