mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
blockchain: Implement initial blockstore API.
This commit is contained in:
@@ -201,7 +201,10 @@ blockchain = [
|
||||
]
|
||||
|
||||
blockchain2 = [
|
||||
"blake3",
|
||||
"sled",
|
||||
|
||||
"util",
|
||||
]
|
||||
|
||||
system = [
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user