use common::transaction::NSSATransaction; use super::*; impl RocksDBIO { pub fn get_block_batch(&self, before: Option, limit: u64) -> DbResult> { let mut seq = vec![]; // Determine the starting block ID let start_block_id = if let Some(before_id) = before { before_id.saturating_sub(1) } else { // Get the latest block ID self.get_meta_last_block_in_db()? }; for i in 0..limit { let block_id = start_block_id.saturating_sub(i); if block_id == 0 { break; } seq.push(block_id); } self.get_block_batch_seq(seq.into_iter()) } /// Get block batch from a sequence /// /// Currently assumes non-decreasing sequence /// /// ToDo: Add suport of arbitrary sequences pub fn get_block_batch_seq(&self, seq: impl Iterator) -> DbResult> { let cf_block = self.block_column(); // Keys setup let mut keys = vec![]; for block_id in seq { keys.push(( &cf_block, borsh::to_vec(&block_id).map_err(|err| { DbError::borsh_cast_message( err, Some("Failed to serialize block id".to_owned()), ) })?, )); } let multi_get_res = self.db.multi_get_cf(keys); // Keys parsing let mut block_batch = vec![]; for res in multi_get_res { let res = res.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; let block = if let Some(data) = res { Ok(borsh::from_slice::(&data).map_err(|serr| { DbError::borsh_cast_message( serr, Some("Failed to deserialize block data".to_owned()), ) })?) } else { // Block not found, assuming that previous one was the last break; }?; block_batch.push(block); } Ok(block_batch) } /// Get block ids by txs /// /// Transactions must be sorted by time of arrival /// /// ToDo: There may be multiple transactions in one block /// so this method can take redundant reads. /// Need to update signature and implementation. fn get_block_ids_by_tx_vec(&self, tx_vec: &[[u8; 32]]) -> DbResult> { let cf_tti = self.tx_hash_to_id_column(); // Keys setup let mut keys = vec![]; for tx_hash in tx_vec { keys.push(( &cf_tti, borsh::to_vec(tx_hash).map_err(|err| { DbError::borsh_cast_message(err, Some("Failed to serialize tx_hash".to_owned())) })?, )); } let multi_get_res = self.db.multi_get_cf(keys); // Keys parsing let mut block_id_batch = vec![]; for res in multi_get_res { let res = res.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; let block_id = if let Some(data) = res { Ok(borsh::from_slice::(&data).map_err(|serr| { DbError::borsh_cast_message( serr, Some("Failed to deserialize block id".to_owned()), ) })?) } else { // Block not found, assuming that previous one was the last break; }?; block_id_batch.push(block_id); } Ok(block_id_batch) } // Account pub(crate) fn get_acc_transaction_hashes( &self, acc_id: [u8; 32], offset: u64, limit: u64, ) -> DbResult> { let cf_att = self.account_id_to_tx_hash_column(); let mut tx_batch = vec![]; // Keys preparation let mut keys = vec![]; for tx_id in offset..(offset + limit) { let mut prefix = borsh::to_vec(&acc_id).map_err(|berr| { DbError::borsh_cast_message(berr, Some("Failed to serialize account id".to_owned())) })?; let suffix = borsh::to_vec(&tx_id).map_err(|berr| { DbError::borsh_cast_message(berr, Some("Failed to serialize tx id".to_owned())) })?; prefix.extend_from_slice(&suffix); keys.push((&cf_att, prefix)); } let multi_get_res = self.db.multi_get_cf(keys); for res in multi_get_res { let res = res.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; let tx_hash = if let Some(data) = res { Ok(borsh::from_slice::<[u8; 32]>(&data).map_err(|serr| { DbError::borsh_cast_message( serr, Some("Failed to deserialize tx_hash".to_owned()), ) })?) } else { // Tx hash not found, assuming that previous one was the last break; }?; tx_batch.push(tx_hash); } Ok(tx_batch) } pub fn get_acc_transactions( &self, acc_id: [u8; 32], offset: u64, limit: u64, ) -> DbResult> { let mut tx_batch = vec![]; let tx_hashes = self.get_acc_transaction_hashes(acc_id, offset, limit)?; let associated_blocks_multi_get = self .get_block_batch_seq(self.get_block_ids_by_tx_vec(&tx_hashes)?.into_iter())? .into_iter() .zip(tx_hashes); for (block, tx_hash) in associated_blocks_multi_get { let transaction = block .body .transactions .iter() .find(|tx| tx.hash().0 == tx_hash) .ok_or(DbError::db_interaction_error(format!( "Missing transaction in block {} with hash {:#?}", block.header.block_id, tx_hash )))?; tx_batch.push(transaction.clone()); } Ok(tx_batch) } }