mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
blockchain: Implement some general query functions.
This commit is contained in:
@@ -3,7 +3,7 @@ use sled::Batch;
|
||||
use crate::{
|
||||
consensus2::{util::Timestamp, Block},
|
||||
util::serial::{deserialize, serialize},
|
||||
Result,
|
||||
Error, Result,
|
||||
};
|
||||
|
||||
const SLED_BLOCK_TREE: &[u8] = b"_blocks";
|
||||
@@ -46,14 +46,18 @@ impl BlockStore {
|
||||
/// Fetch given blockhashes from the blockstore.
|
||||
/// The resulting vector contains `Option` which is `Some` if the block
|
||||
/// was found in the blockstore, and `None`, if it has not.
|
||||
pub fn get(&self, blockhashes: &[blake3::Hash]) -> Result<Vec<Option<Block>>> {
|
||||
let mut ret: Vec<Option<Block>> = Vec::with_capacity(blockhashes.len());
|
||||
pub fn get(&self, blockhashes: &[blake3::Hash], strict: bool) -> Result<Vec<Option<Block>>> {
|
||||
let mut ret = Vec::with_capacity(blockhashes.len());
|
||||
|
||||
for i in blockhashes {
|
||||
if let Some(found) = self.0.get(i.as_bytes())? {
|
||||
let block = deserialize(&found)?;
|
||||
ret.push(Some(block));
|
||||
} else {
|
||||
if strict {
|
||||
let s = i.to_hex().as_str().to_string();
|
||||
return Err(Error::BlockNotFound(s))
|
||||
}
|
||||
ret.push(None);
|
||||
}
|
||||
}
|
||||
@@ -113,6 +117,26 @@ impl BlockOrderStore {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieve all hashes given slots.
|
||||
pub fn get(&self, slots: &[u64], strict: bool) -> Result<Vec<Option<blake3::Hash>>> {
|
||||
let mut ret = Vec::with_capacity(slots.len());
|
||||
|
||||
for i in slots {
|
||||
if let Some(found) = self.0.get(i.to_be_bytes())? {
|
||||
let hash_bytes: [u8; 32] = found.as_ref().try_into().unwrap();
|
||||
let hash = blake3::Hash::from(hash_bytes);
|
||||
ret.push(Some(hash));
|
||||
} else {
|
||||
if strict {
|
||||
return Err(Error::SlotNotFound(*i))
|
||||
}
|
||||
ret.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Retrieve the last block hash in the tree, based on the Ord
|
||||
/// implementation for Vec<u8>.
|
||||
pub fn get_last(&self) -> Result<Option<(u64, blake3::Hash)>> {
|
||||
|
||||
@@ -3,7 +3,7 @@ use sled::Batch;
|
||||
use crate::{
|
||||
consensus2::StreamletMetadata,
|
||||
util::serial::{deserialize, serialize},
|
||||
Result,
|
||||
Error, Result,
|
||||
};
|
||||
|
||||
const SLED_STREAMLET_METADATA_TREE: &[u8] = b"_streamlet_metadata";
|
||||
@@ -31,6 +31,30 @@ impl StreamletMetadataStore {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieve `StreamletMetadata` by given blockhashes.
|
||||
pub fn get(
|
||||
&self,
|
||||
blockhashes: &[blake3::Hash],
|
||||
strict: bool,
|
||||
) -> Result<Vec<Option<StreamletMetadata>>> {
|
||||
let mut ret = Vec::with_capacity(blockhashes.len());
|
||||
|
||||
for i in blockhashes {
|
||||
if let Some(found) = self.0.get(i.as_bytes())? {
|
||||
let sm = deserialize(&found)?;
|
||||
ret.push(Some(sm));
|
||||
} else {
|
||||
if strict {
|
||||
let s = i.to_hex().as_str().to_string();
|
||||
return Err(Error::BlockMetadataNotFound(s))
|
||||
}
|
||||
ret.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Retrieve all `StreamletMetadata`.
|
||||
/// Be careful as this will try to lead everything in memory.
|
||||
pub fn get_all(&self) -> Result<Vec<Option<(blake3::Hash, StreamletMetadata)>>> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::io;
|
||||
|
||||
use crate::{
|
||||
consensus2::{block::BlockProposal, util::Timestamp, Block},
|
||||
consensus2::{block::BlockInfo, util::Timestamp, Block, BlockProposal},
|
||||
impl_vec,
|
||||
util::serial::{Decodable, Encodable, ReadExt, VarInt, WriteExt},
|
||||
Result,
|
||||
@@ -49,31 +49,76 @@ impl Blockchain {
|
||||
Ok(Self { blocks, order, transactions, streamlet_metadata, nullifiers, merkle_roots })
|
||||
}
|
||||
|
||||
/// Batch insert [`BlockProposal`]s.
|
||||
pub fn add(&mut self, proposals: &[BlockProposal]) -> Result<Vec<blake3::Hash>> {
|
||||
// TODO: Engineer this function in a better way.
|
||||
let mut ret = Vec::with_capacity(proposals.len());
|
||||
/// Batch insert [`BlockInfo`]s.
|
||||
pub fn add(&mut self, blocks: &[BlockInfo]) -> Result<Vec<blake3::Hash>> {
|
||||
let mut ret = Vec::with_capacity(blocks.len());
|
||||
|
||||
for prop in proposals {
|
||||
for block in blocks {
|
||||
// Store transactions
|
||||
let tx_hashes = self.transactions.insert(&prop.txs)?;
|
||||
let tx_hashes = self.transactions.insert(&block.txs)?;
|
||||
|
||||
// Store block
|
||||
let block =
|
||||
Block { st: prop.st, sl: prop.sl, txs: tx_hashes, metadata: prop.metadata.clone() };
|
||||
let blockhash = self.blocks.insert(&[block.clone()])?;
|
||||
let _block = Block::new(block.st, block.sl, tx_hashes, block.metadata.clone());
|
||||
let blockhash = self.blocks.insert(&[_block])?;
|
||||
ret.push(blockhash[0]);
|
||||
|
||||
// Store block order
|
||||
self.order.insert(&[block.sl], &[blockhash[0]])?;
|
||||
|
||||
// Store streamlet metadata
|
||||
self.streamlet_metadata.insert(&[blockhash[0]], &[prop.sm.clone()])?;
|
||||
// Store Streamlet metadata
|
||||
self.streamlet_metadata.insert(&[blockhash[0]], &[block.sm.clone()])?;
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Retrieve blocks by given hashes. Fails if any of them are not found.
|
||||
pub fn get_blocks_by_hash(&self, blockhashes: &[blake3::Hash]) -> Result<Vec<BlockInfo>> {
|
||||
let mut ret = Vec::with_capacity(blockhashes.len());
|
||||
|
||||
let blocks = self.blocks.get(blockhashes, true)?;
|
||||
let metadata = self.streamlet_metadata.get(blockhashes, true)?;
|
||||
|
||||
for (i, block) in blocks.iter().enumerate() {
|
||||
let block = block.clone().unwrap();
|
||||
let sm = metadata[i].clone().unwrap();
|
||||
|
||||
let txs = self.transactions.get(&block.txs, true)?;
|
||||
let txs = txs.iter().map(|x| x.clone().unwrap()).collect();
|
||||
|
||||
let info = BlockInfo::new(block.st, block.sl, txs, block.metadata.clone(), sm);
|
||||
ret.push(info);
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Retrieve blocks by given slots. Fails if any of them are not found.
|
||||
pub fn get_blocks_by_slot(&self, slots: &[u64]) -> Result<Vec<BlockInfo>> {
|
||||
let blockhashes = self.order.get(slots, true)?;
|
||||
let blockhashes: Vec<blake3::Hash> = blockhashes.iter().map(|x| x.unwrap()).collect();
|
||||
self.get_blocks_by_hash(&blockhashes)
|
||||
}
|
||||
|
||||
/// Check if the given [`BlockInfo`] is in the database
|
||||
pub fn has_block(&self, info: &BlockInfo) -> Result<bool> {
|
||||
let hashes = self.order.get(&[info.sl], true)?;
|
||||
if hashes.is_empty() {
|
||||
return Ok(false)
|
||||
}
|
||||
|
||||
if let Some(found) = &hashes[0] {
|
||||
// Check provided info produces the same hash
|
||||
// TODO: This BlockProposal::to_proposal_hash function should be in a better place.
|
||||
let blockhash =
|
||||
BlockProposal::to_proposal_hash(info.st, info.sl, &info.txs, &info.metadata);
|
||||
|
||||
return Ok(&blockhash == found)
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Retrieve the last block slot and hash
|
||||
pub fn last(&self) -> Result<Option<(u64, blake3::Hash)>> {
|
||||
self.order.get_last()
|
||||
|
||||
@@ -3,7 +3,7 @@ use sled::Batch;
|
||||
use crate::{
|
||||
consensus2::Tx,
|
||||
util::serial::{deserialize, serialize},
|
||||
Result,
|
||||
Error, Result,
|
||||
};
|
||||
|
||||
const SLED_TX_TREE: &[u8] = b"_transactions";
|
||||
@@ -35,6 +35,27 @@ impl TxStore {
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Fetch requested transactions from the txstore. The `strict` param
|
||||
/// will make the function fail if a transaction has not been found.
|
||||
pub fn get(&self, tx_hashes: &[blake3::Hash], strict: bool) -> Result<Vec<Option<Tx>>> {
|
||||
let mut ret: Vec<Option<Tx>> = Vec::with_capacity(tx_hashes.len());
|
||||
|
||||
for i in tx_hashes {
|
||||
if let Some(found) = self.0.get(i.as_bytes())? {
|
||||
let tx = deserialize(&found)?;
|
||||
ret.push(Some(tx));
|
||||
} else {
|
||||
if strict {
|
||||
let s = i.to_hex().as_str().to_string();
|
||||
return Err(Error::TransactionNotFound(s))
|
||||
}
|
||||
ret.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Retrieve all transactions.
|
||||
/// Be careful as this will try to load everything in memory.
|
||||
pub fn get_all(&self) -> Result<Vec<Option<(blake3::Hash, Tx)>>> {
|
||||
|
||||
12
src/error.rs
12
src/error.rs
@@ -184,6 +184,18 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
SledError(#[from] sled::Error),
|
||||
|
||||
#[error("Transaction {0} not found in database")]
|
||||
TransactionNotFound(String),
|
||||
|
||||
#[error("Block {0} not found in database")]
|
||||
BlockNotFound(String),
|
||||
|
||||
#[error("Block in slot {0} not found in database")]
|
||||
SlotNotFound(u64),
|
||||
|
||||
#[error("Block {0} metadata not found in database")]
|
||||
BlockMetadataNotFound(String),
|
||||
|
||||
// =============
|
||||
// Wallet errors
|
||||
// =============
|
||||
|
||||
Reference in New Issue
Block a user