diff --git a/src/blockchain/block_store.rs b/src/blockchain/block_store.rs index 0c2fb8710..a2701f27e 100644 --- a/src/blockchain/block_store.rs +++ b/src/blockchain/block_store.rs @@ -21,7 +21,7 @@ use darkfi_serial::{deserialize, serialize, SerialDecodable, SerialEncodable}; use crate::{tx::Transaction, Error, Result}; -use super::{Header, SledDbOverlayPtr}; +use super::{parse_record, Header, SledDbOverlayPtr}; /// Block version number pub const BLOCK_VERSION: u8 = 1; @@ -66,7 +66,7 @@ impl Block { /// Structure representing full block data. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)] pub struct BlockInfo { - /// BlockInfo magic bytes + /// Block magic bytes pub magic: [u8; 4], /// Block header data pub header: Header, @@ -205,7 +205,7 @@ impl BlockStore { /// Generate the sled batch corresponding to an insert, so caller /// can handle the write operation. - /// The blocks are hashed with BLAKE3 and this blockhash is used as + /// The blocks are hashed with BLAKE3 and this block hash is used as /// the key, while value is the serialized [`Block`] itself. /// On success, the function returns the block hashes in the same order. pub fn insert_batch(&self, blocks: &[Block]) -> Result<(sled::Batch, Vec)> { @@ -222,14 +222,14 @@ impl BlockStore { Ok((batch, ret)) } - /// Check if the blockstore contains a given blockhash. + /// Check if the block store contains a given block hash. pub fn contains(&self, blockhash: &blake3::Hash) -> Result { Ok(self.0.contains_key(blockhash.as_bytes())?) } - /// Fetch given block hashes from the blockstore. + /// Fetch given block hashes from the block store. /// The resulting vector contains `Option`, which is `Some` if the block - /// was found in the blockstore, and otherwise it is `None`, if it has not. + /// was found in the block store, and otherwise it is `None`, if it has not. /// The second parameter is a boolean which tells the function to fail in /// case at least one block was not found. pub fn get(&self, block_hashes: &[blake3::Hash], strict: bool) -> Result>> { @@ -251,17 +251,14 @@ impl BlockStore { Ok(ret) } - /// Retrieve all blocks from the blockstore in the form of a tuple - /// (`blockhash`, `block`). + /// Retrieve all blocks from the block store in the form of a tuple + /// (`hash`, `block`). /// Be careful as this will try to load everything in memory. pub fn get_all(&self) -> Result> { let mut blocks = vec![]; for block in self.0.iter() { - let (key, value) = block.unwrap(); - let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap(); - let block = deserialize(&value)?; - blocks.push((hash_bytes.into(), block)); + blocks.push(parse_record(block.unwrap())?); } Ok(blocks) @@ -278,7 +275,7 @@ impl BlockStoreOverlay { } /// Insert a slice of [`Block`] into the overlay. - /// The block are hashed with BLAKE3 and this blockhash is used as + /// The block are hashed with BLAKE3 and this block hash is used as /// the key, while value is the serialized [`Block`] itself. /// On success, the function returns the block hashes in the same order. pub fn insert(&self, blocks: &[Block]) -> Result> { @@ -324,9 +321,9 @@ impl BlockStoreOverlay { /// Auxiliary structure used to keep track of blocks order. #[derive(Debug, SerialEncodable, SerialDecodable)] pub struct BlockOrder { - /// Slot UID - pub slot: u64, - /// Block headerhash of that slot + /// Order number + pub number: u64, + /// Block headerhash of that number pub block: blake3::Hash, } @@ -334,7 +331,7 @@ pub struct BlockOrder { const SLED_BLOCK_ORDER_TREE: &[u8] = b"_block_order"; /// The `BlockOrderStore` is a `sled` tree storing the order of the -/// blockchain's slots, where the key is the slot uid, and the value is +/// blockchain's blocks, where the key is the order number, and the value is /// the blocks' hash. [`BlockStore`] can be queried with this hash. #[derive(Clone)] pub struct BlockOrderStore(pub sled::Tree); @@ -346,51 +343,50 @@ impl BlockOrderStore { Ok(Self(tree)) } - /// Insert a slice of slots and blockhashes into the store. - pub fn insert(&self, slots: &[u64], hashes: &[blake3::Hash]) -> Result<()> { - let batch = self.insert_batch(slots, hashes)?; + /// Insert a slice of `u64` and block hashes into the store. + pub fn insert(&self, order: &[u64], hashes: &[blake3::Hash]) -> Result<()> { + let batch = self.insert_batch(order, hashes)?; self.0.apply_batch(batch)?; Ok(()) } /// Generate the sled batch corresponding to an insert, so caller /// can handle the write operation. - /// The block slot is used as the key, and the blockhash is used as value. - pub fn insert_batch(&self, slots: &[u64], hashes: &[blake3::Hash]) -> Result { - if slots.len() != hashes.len() { + /// The block order number is used as the key, and the block hash is used as value. + pub fn insert_batch(&self, order: &[u64], hashes: &[blake3::Hash]) -> Result { + if order.len() != hashes.len() { return Err(Error::InvalidInputLengths) } let mut batch = sled::Batch::default(); - for (i, sl) in slots.iter().enumerate() { - batch.insert(&sl.to_be_bytes(), hashes[i].as_bytes()); + for (i, number) in order.iter().enumerate() { + batch.insert(&number.to_be_bytes(), hashes[i].as_bytes()); } Ok(batch) } - /// Check if the blockorderstore contains a given slot. - pub fn contains(&self, slot: u64) -> Result { - Ok(self.0.contains_key(slot.to_be_bytes())?) + /// Check if the block order store contains a given order number. + pub fn contains(&self, number: u64) -> Result { + Ok(self.0.contains_key(number.to_be_bytes())?) } - /// Fetch given slots from the blockorderstore. - /// The resulting vector contains `Option`, which is `Some` if the slot - /// was found in the blockstore, and otherwise it is `None`, if it has not. + /// Fetch given order numbers from the block order store. + /// The resulting vector contains `Option`, which is `Some` if the number + /// was found in the block order store, and otherwise it is `None`, if it has not. /// The second parameter is a boolean which tells the function to fail in - /// case at least one slot was not found. - pub fn get(&self, slots: &[u64], strict: bool) -> Result>> { - let mut ret = Vec::with_capacity(slots.len()); + /// case at least one order number was not found. + pub fn get(&self, order: &[u64], strict: bool) -> Result>> { + let mut ret = Vec::with_capacity(order.len()); - for slot in slots { - if let Some(found) = self.0.get(slot.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)); + for number in order { + if let Some(found) = self.0.get(number.to_be_bytes())? { + let block_hash = deserialize(&found)?; + ret.push(Some(block_hash)); } else { if strict { - return Err(Error::BlockSlotNotFound(*slot)) + return Err(Error::BlockNumberNotFound(*number)) } ret.push(None); } @@ -399,38 +395,32 @@ impl BlockOrderStore { Ok(ret) } - /// Retrieve all slots from the blockorderstore in the form of a tuple - /// (`slot`, `blockhash`). + /// Retrieve complete order from the block order store in the form of + /// a vector containing (`number`, `hash`) tuples. /// Be careful as this will try to load everything in memory. pub fn get_all(&self) -> Result> { - let mut slots = vec![]; + let mut order = vec![]; - for slot in self.0.iter() { - let (key, value) = slot.unwrap(); - let slot_bytes: [u8; 8] = key.as_ref().try_into().unwrap(); - let hash_bytes: [u8; 32] = value.as_ref().try_into().unwrap(); - let slot = u64::from_be_bytes(slot_bytes); - let hash = blake3::Hash::from(hash_bytes); - slots.push((slot, hash)); + for record in self.0.iter() { + order.push(parse_record(record.unwrap())?); } - Ok(slots) + Ok(order) } - /// Fetch n hashes after given slot. In the iteration, if a slot is not - /// found, the iteration stops and the function returns what it has found - /// so far in the `BlockOrderStore`. - pub fn get_after(&self, slot: u64, n: u64) -> Result> { + /// Fetch n hashes after given order number. In the iteration, if an order + /// number is not found, the iteration stops and the function returns what + /// it has found so far in the `BlockOrderStore`. + pub fn get_after(&self, number: u64, n: u64) -> Result> { let mut ret = vec![]; - let mut key = slot; + let mut key = number; let mut counter = 0; while counter <= n { if let Some(found) = self.0.get_gt(key.to_be_bytes())? { - let key_bytes: [u8; 8] = found.0.as_ref().try_into().unwrap(); - key = u64::from_be_bytes(key_bytes); - let blockhash = deserialize(&found.1)?; - ret.push(blockhash); + let (number, hash) = parse_record(found)?; + key = number; + ret.push(hash); counter += 1; continue } @@ -440,33 +430,25 @@ impl BlockOrderStore { Ok(ret) } - /// Fetch the first blockhash in the tree, based on the `Ord` + /// Fetch the first block hash in the tree, based on the `Ord` /// implementation for `Vec`. pub fn get_first(&self) -> Result<(u64, blake3::Hash)> { let found = match self.0.first()? { Some(s) => s, - None => return Err(Error::SlotNotFound(0)), + None => return Err(Error::BlockNumberNotFound(0)), }; + let (number, hash) = parse_record(found)?; - let slot_bytes: [u8; 8] = found.0.as_ref().try_into().unwrap(); - let hash_bytes: [u8; 32] = found.1.as_ref().try_into().unwrap(); - let slot = u64::from_be_bytes(slot_bytes); - let hash = blake3::Hash::from(hash_bytes); - - Ok((slot, hash)) + Ok((number, hash)) } - /// Fetch the last blockhash in the tree, based on the `Ord` + /// Fetch the last block hash in the tree, based on the `Ord` /// implementation for `Vec`. pub fn get_last(&self) -> Result<(u64, blake3::Hash)> { let found = self.0.last()?.unwrap(); + let (number, hash) = parse_record(found)?; - let slot_bytes: [u8; 8] = found.0.as_ref().try_into().unwrap(); - let hash_bytes: [u8; 32] = found.1.as_ref().try_into().unwrap(); - let slot = u64::from_be_bytes(slot_bytes); - let hash = blake3::Hash::from(hash_bytes); - - Ok((slot, hash)) + Ok((number, hash)) } /// Retrieve records count @@ -489,40 +471,39 @@ impl BlockOrderStoreOverlay { Ok(Self(overlay)) } - /// Insert a slice of slots and blockhashes into the store. With sled, the + /// Insert a slice of `u64` and block hashes into the store. With sled, the /// operation is done as a batch. - /// The block slot is used as the key, and the blockhash is used as value. - pub fn insert(&self, slots: &[u64], hashes: &[blake3::Hash]) -> Result<()> { - if slots.len() != hashes.len() { + /// The block order number is used as the key, and the blockhash is used as value. + pub fn insert(&self, order: &[u64], hashes: &[blake3::Hash]) -> Result<()> { + if order.len() != hashes.len() { return Err(Error::InvalidInputLengths) } let mut lock = self.0.lock().unwrap(); - for (i, sl) in slots.iter().enumerate() { - lock.insert(SLED_BLOCK_ORDER_TREE, &sl.to_be_bytes(), hashes[i].as_bytes())?; + for (i, number) in order.iter().enumerate() { + lock.insert(SLED_BLOCK_ORDER_TREE, &number.to_be_bytes(), hashes[i].as_bytes())?; } Ok(()) } - /// Fetch given slots from the overlay. - /// The resulting vector contains `Option`, which is `Some` if the slot + /// Fetch given order numbers from the overlay. + /// The resulting vector contains `Option`, which is `Some` if the number /// was found in the overlay, and otherwise it is `None`, if it has not. /// The second parameter is a boolean which tells the function to fail in - /// case at least one slot was not found. - pub fn get(&self, slots: &[u64], strict: bool) -> Result>> { - let mut ret = Vec::with_capacity(slots.len()); + /// case at least one number was not found. + pub fn get(&self, order: &[u64], strict: bool) -> Result>> { + let mut ret = Vec::with_capacity(order.len()); let lock = self.0.lock().unwrap(); - for slot in slots { - if let Some(found) = lock.get(SLED_BLOCK_ORDER_TREE, &slot.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)); + for number in order { + if let Some(found) = lock.get(SLED_BLOCK_ORDER_TREE, &number.to_be_bytes())? { + let block_hash = deserialize(&found)?; + ret.push(Some(block_hash)); } else { if strict { - return Err(Error::BlockSlotNotFound(*slot)) + return Err(Error::BlockNumberNotFound(*number)) } ret.push(None); } @@ -531,17 +512,13 @@ impl BlockOrderStoreOverlay { Ok(ret) } - /// Fetch the last blockhash in the overlay, based on the `Ord` + /// Fetch the last block hash in the overlay, based on the `Ord` /// implementation for `Vec`. pub fn get_last(&self) -> Result<(u64, blake3::Hash)> { let found = self.0.lock().unwrap().last(SLED_BLOCK_ORDER_TREE)?.unwrap(); + let (number, hash) = parse_record(found)?; - let slot_bytes: [u8; 8] = found.0.as_ref().try_into().unwrap(); - let hash_bytes: [u8; 32] = found.1.as_ref().try_into().unwrap(); - let slot = u64::from_be_bytes(slot_bytes); - let hash = blake3::Hash::from(hash_bytes); - - Ok((slot, hash)) + Ok((number, hash)) } /// Check if overlay contains any records diff --git a/src/blockchain/header_store.rs b/src/blockchain/header_store.rs index 7d78f16bc..7104fbdaa 100644 --- a/src/blockchain/header_store.rs +++ b/src/blockchain/header_store.rs @@ -21,7 +21,7 @@ use darkfi_serial::{deserialize, serialize, SerialDecodable, SerialEncodable}; use crate::{util::time::Timestamp, Error, Result}; -use super::{block_store::BLOCK_VERSION, SledDbOverlayPtr}; +use super::{block_store::BLOCK_VERSION, parse_record, SledDbOverlayPtr}; /// This struct represents a tuple of the form (version, previous, epoch, slot, timestamp, merkle_root). #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)] @@ -52,12 +52,6 @@ impl Header { Self { version, previous, epoch, slot, timestamp, root } } - /// Generate the genesis block for provided genesis info. - pub fn genesis_header(genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Self { - let root = MerkleTree::new(100).root(0).unwrap(); - Self::new(genesis_data, 0, 0, genesis_ts, root) - } - /// Calculate the header hash pub fn headerhash(&self) -> blake3::Hash { blake3::hash(&serialize(self)) @@ -155,10 +149,7 @@ impl HeaderStore { let mut headers = vec![]; for header in self.0.iter() { - let (key, value) = header.unwrap(); - let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap(); - let header = deserialize(&value)?; - headers.push((hash_bytes.into(), header)); + headers.push(parse_record(header.unwrap())?); } Ok(headers) diff --git a/src/blockchain/mod.rs b/src/blockchain/mod.rs index d2e6814bd..0206ec163 100644 --- a/src/blockchain/mod.rs +++ b/src/blockchain/mod.rs @@ -22,24 +22,29 @@ use log::debug; use sled::Transactional; use darkfi_sdk::blockchain::Slot; -use darkfi_serial::serialize; +use darkfi_serial::{deserialize, serialize, Decodable}; use crate::{tx::Transaction, Error, Result}; +/// Block related definitions and storage implementations pub mod block_store; pub use block_store::{ Block, BlockInfo, BlockOrderStore, BlockOrderStoreOverlay, BlockStore, BlockStoreOverlay, }; +/// Header definition and storage implementation pub mod header_store; pub use header_store::{Header, HeaderStore, HeaderStoreOverlay}; +/// Slots storage implementation pub mod slot_store; pub use slot_store::{SlotStore, SlotStoreOverlay}; +/// Transactions related storage implementations pub mod tx_store; pub use tx_store::{PendingTxOrderStore, PendingTxStore, TxStore, TxStoreOverlay}; +/// Contracts and Wasm storage implementations pub mod contract_store; pub use contract_store::{ ContractStateStore, ContractStateStoreOverlay, WasmStore, WasmStoreOverlay, @@ -525,3 +530,13 @@ impl BlockchainOverlay { Ok(()) } } + +/// Parse a sled record in the form of a tuple (`key`, `value`). +pub fn parse_record( + record: (sled::IVec, sled::IVec), +) -> Result<(T1, T2)> { + let key = deserialize(&record.0)?; + let value = deserialize(&record.1)?; + + Ok((key, value)) +} diff --git a/src/blockchain/slot_store.rs b/src/blockchain/slot_store.rs index 4842cab81..cac80bf1b 100644 --- a/src/blockchain/slot_store.rs +++ b/src/blockchain/slot_store.rs @@ -22,7 +22,7 @@ use darkfi_serial::{deserialize, serialize}; use crate::{Error, Result}; -use super::SledDbOverlayPtr; +use super::{parse_record, SledDbOverlayPtr}; const SLED_SLOT_TREE: &[u8] = b"_slots"; @@ -93,8 +93,7 @@ impl SlotStore { let mut slots = vec![]; for slot in self.0.iter() { - let (_, value) = slot.unwrap(); - let slot = deserialize(&value)?; + let (_, slot): ([u8; 8], Slot) = parse_record(slot.unwrap())?; slots.push(slot); } @@ -111,9 +110,8 @@ impl SlotStore { let mut counter = 0; while counter <= n { if let Some(found) = self.0.get_gt(key.to_be_bytes())? { - let key_bytes: [u8; 8] = found.0.as_ref().try_into().unwrap(); - key = u64::from_be_bytes(key_bytes); - let slot = deserialize(&found.1)?; + let (id, slot) = parse_record(found)?; + key = id; ret.push(slot); counter += 1; continue diff --git a/src/blockchain/tx_store.rs b/src/blockchain/tx_store.rs index 17c6b7cda..eaffb5961 100644 --- a/src/blockchain/tx_store.rs +++ b/src/blockchain/tx_store.rs @@ -22,7 +22,7 @@ use darkfi_serial::{deserialize, serialize}; use crate::{tx::Transaction, Error, Result}; -use super::SledDbOverlayPtr; +use super::{parse_record, SledDbOverlayPtr}; const SLED_TX_TREE: &[u8] = b"_transactions"; const SLED_PENDING_TX_TREE: &[u8] = b"_pending_transactions"; @@ -112,10 +112,7 @@ impl TxStore { let mut txs = vec![]; for tx in self.0.iter() { - let (key, value) = tx.unwrap(); - let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap(); - let tx = deserialize(&value)?; - txs.push((hash_bytes.into(), tx)); + txs.push(parse_record(tx.unwrap())?); } Ok(txs) @@ -246,10 +243,8 @@ impl PendingTxStore { let mut txs = HashMap::new(); for tx in self.0.iter() { - let (key, value) = tx.unwrap(); - let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap(); - let tx = deserialize(&value)?; - txs.insert(hash_bytes.into(), tx); + let (key, value) = parse_record(tx.unwrap())?; + txs.insert(key, value); } Ok(txs) @@ -325,12 +320,7 @@ impl PendingTxOrderStore { let mut txs = vec![]; for tx in self.0.iter() { - let (key, value) = tx.unwrap(); - let index_bytes: [u8; 8] = key.as_ref().try_into().unwrap(); - let hash_bytes: [u8; 32] = value.as_ref().try_into().unwrap(); - let index = u64::from_be_bytes(index_bytes); - let hash = blake3::Hash::from(hash_bytes); - txs.push((index, hash)); + txs.push(parse_record(tx.unwrap())?); } Ok(txs) diff --git a/src/error.rs b/src/error.rs index 8a18e4e53..cf5b69828 100644 --- a/src/error.rs +++ b/src/error.rs @@ -312,8 +312,8 @@ pub enum Error { #[error("Block {0} not found in database")] BlockNotFound(String), - #[error("Block in slot {0} not found in database")] - BlockSlotNotFound(u64), + #[error("Block with order number {0} not found in database")] + BlockNumberNotFound(u64), #[error("Slot {0} not found in database")] SlotNotFound(u64),