blockchain: Implement initial blockstore API.

This commit is contained in:
parazyd
2022-04-03 15:24:56 +02:00
parent 0109aa0394
commit 4a4b40d7be
3 changed files with 127 additions and 1 deletions

View File

@@ -201,7 +201,10 @@ blockchain = [
]
blockchain2 = [
"blake3",
"sled",
"util",
]
system = [

View File

@@ -1,12 +1,110 @@
use crate::Result;
use crate::{
util::serial::{deserialize, serialize, SerialDecodable, SerialEncodable},
Result,
};
const SLED_BLOCK_TREE: &[u8] = b"_blocks";
// TODO: The block structure should be as follows
#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
pub struct Block {
/// Previous block hash (blake3)
pub st: blake3::Hash,
/// Slot UID, generated by the beacon
pub sl: u64,
/// Transaction hashes (blake3)
/// The actual transactions are in [`TxStore`]
pub txs: Vec<blake3::Hash>,
/// Additional block information
pub metadata: String,
}
pub struct BlockStore(sled::Tree);
impl BlockStore {
/// Opens a new or existing blockstore tree given a sled database.
pub fn new(db: &sled::Db) -> Result<Self> {
let tree = db.open_tree(SLED_BLOCK_TREE)?;
Ok(Self(tree))
}
/// Insert a vector of [`Block`] into the blockstore.
/// The blocks are hashed with blake3 and this blockhash is used as
// the key, where value is the serialized block itself.
pub fn insert(&self, blocks: Vec<Block>) -> Result<()> {
for i in &blocks {
let serialized = serialize(i);
let blockhash = blake3::hash(&serialized);
self.0.insert(blockhash.as_bytes(), serialized)?;
}
Ok(())
}
/// 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: Vec<blake3::Hash>) -> Result<Vec<Option<Block>>> {
let mut ret: Vec<Option<Block>> = 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 {
ret.push(None);
}
}
Ok(ret)
}
/// Check if the blockstore contains a given blockhash.
pub fn contains(&self, blockhash: blake3::Hash) -> Result<bool> {
Ok(self.0.contains_key(blockhash.as_bytes())?)
}
/// Fetch the first (oldest) block in the tree.
pub fn get_first(&self) -> Result<Option<(blake3::Hash, Block)>> {
if let Some(found) = self.0.first()? {
let hash_bytes: [u8; 32] = found.0.as_ref().try_into().unwrap();
let block = deserialize(&found.1)?;
return Ok(Some((hash_bytes.into(), block)))
}
Ok(None)
}
/// Fetch the last (newest) block in the tree.
pub fn get_last(&self) -> Result<Option<(blake3::Hash, Block)>> {
if let Some(found) = self.0.last()? {
let hash_bytes: [u8; 32] = found.0.as_ref().try_into().unwrap();
let block = deserialize(&found.1)?;
return Ok(Some((hash_bytes.into(), block)))
}
Ok(None)
}
/// Fetch the block and its hash before the provided blockhash, if one exists.
pub fn get_lt(&self, blockhash: blake3::Hash) -> Result<Option<(blake3::Hash, Block)>> {
if let Some(found) = self.0.get_lt(blockhash.as_bytes())? {
let hash_bytes: [u8; 32] = found.0.as_ref().try_into().unwrap();
let block = deserialize(&found.1)?;
return Ok(Some((hash_bytes.into(), block)))
}
Ok(None)
}
/// Fetch the block and its hash after the provided blockhash, if one exists.
pub fn get_gt(&self, blockhash: blake3::Hash) -> Result<Option<(blake3::Hash, Block)>> {
if let Some(found) = self.0.get_gt(blockhash.as_bytes())? {
let hash_bytes: [u8; 32] = found.0.as_ref().try_into().unwrap();
let block = deserialize(&found.1)?;
return Ok(Some((hash_bytes.into(), block)))
}
Ok(None)
}
}

View File

@@ -1,4 +1,29 @@
use std::io;
use crate::{
impl_vec,
util::serial::{Decodable, Encodable, ReadExt, VarInt, WriteExt},
Result,
};
pub mod blockstore;
pub mod nfstore;
pub mod rootstore;
pub mod txstore;
impl Encodable for blake3::Hash {
fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(self.as_bytes())?;
Ok(32)
}
}
impl Decodable for blake3::Hash {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
let mut bytes = [0u8; 32];
d.read_slice(&mut bytes)?;
Ok(bytes.into())
}
}
impl_vec!(blake3::Hash);