lssa/indexer/core/src/block_store.rs
2026-02-04 14:57:38 +02:00

105 lines
3.0 KiB
Rust

use std::{path::Path, sync::Arc};
use anyhow::Result;
use common::{
block::Block,
transaction::{NSSATransaction, execute_check_transaction_on_state, transaction_pre_check},
};
use nssa::{Account, AccountId, V02State};
use storage::indexer::RocksDBIO;
#[derive(Clone)]
pub struct IndexerStore {
dbio: Arc<RocksDBIO>,
}
impl IndexerStore {
/// Starting database at the start of new chain.
/// Creates files if necessary.
///
/// ATTENTION: Will overwrite genesis block.
pub fn open_db_with_genesis(
location: &Path,
start_data: Option<(Block, V02State)>,
) -> Result<Self> {
let dbio = RocksDBIO::open_or_create(location, start_data)?;
Ok(Self {
dbio: Arc::new(dbio),
})
}
/// Reopening existing database
pub fn open_db_restart(location: &Path) -> Result<Self> {
Self::open_db_with_genesis(location, None)
}
pub fn get_block_at_id(&self, id: u64) -> Result<Block> {
Ok(self.dbio.get_block(id)?)
}
pub fn get_block_batch(&self, offset: u64, limit: u64) -> Result<Vec<Block>> {
Ok(self.dbio.get_block_batch(offset, limit)?)
}
pub fn get_transaction_by_hash(&self, tx_hash: [u8; 32]) -> Result<NSSATransaction> {
let block = self.get_block_at_id(self.dbio.get_block_id_by_tx_hash(tx_hash)?)?;
let encoded_transaction = block
.body
.transactions
.iter()
.find_map(|enc_tx| {
if enc_tx.hash() == tx_hash {
Some(enc_tx)
} else {
None
}
})
.ok_or_else(|| anyhow::anyhow!("Transaction not found in DB"))?;
Ok(NSSATransaction::try_from(encoded_transaction)?)
}
pub fn get_block_by_hash(&self, hash: [u8; 32]) -> Result<Block> {
Ok(self.get_block_at_id(self.dbio.get_block_id_by_hash(hash)?)?)
}
pub fn genesis_id(&self) -> u64 {
self.dbio
.get_meta_first_block_in_db()
.expect("Must be set at the DB startup")
}
pub fn last_block(&self) -> u64 {
self.dbio
.get_meta_last_block_in_db()
.expect("Must be set at the DB startup")
}
pub fn get_state_at_block(&self, block_id: u64) -> Result<V02State> {
Ok(self.dbio.calculate_state_for_id(block_id)?)
}
pub fn final_state(&self) -> Result<V02State> {
Ok(self.dbio.final_state()?)
}
pub fn get_account_final(&self, account_id: &AccountId) -> Result<Account> {
Ok(self.final_state()?.get_account_by_id(account_id))
}
pub fn put_block(&self, block: Block) -> Result<()> {
let mut final_state = self.dbio.final_state()?;
for encoded_transaction in &block.body.transactions {
let transaction = NSSATransaction::try_from(encoded_transaction)?;
execute_check_transaction_on_state(
&mut final_state,
transaction_pre_check(transaction)?,
)?;
}
Ok(self.dbio.put_block(block)?)
}
}