فهرست منبع

blockchain/block_store: unified all trees into a single store structure

skoupidi 2 سال پیش
والد
کامیت
34dd60a9b7
5فایلهای تغییر یافته به همراه410 افزوده شده و 477 حذف شده
  1. 8 8
      bin/darkfid/src/tests/forks.rs
  2. 378 404
      src/blockchain/block_store.rs
  3. 21 62
      src/blockchain/mod.rs
  4. 2 2
      src/validator/pow.rs
  5. 1 1
      src/validator/verification.rs

+ 8 - 8
bin/darkfid/src/tests/forks.rs

@@ -42,12 +42,12 @@ fn forks() -> Result<()> {
         let fork = Fork::new(blockchain.clone(), module).await?;
 
         // Add a dummy record to fork
-        fork.overlay.lock().unwrap().order.insert(&[1], &[record1])?;
+        fork.overlay.lock().unwrap().blocks.insert_order(&[1], &[record1])?;
 
         // Verify blockchain doesn't contain the record
-        assert_eq!(blockchain.order.get(&[0, 1], false)?, [Some(genesis_block_hash), None]);
+        assert_eq!(blockchain.blocks.get_order(&[0, 1], false)?, [Some(genesis_block_hash), None]);
         assert_eq!(
-            fork.overlay.lock().unwrap().order.get(&[0, 1], true)?,
+            fork.overlay.lock().unwrap().blocks.get_order(&[0, 1], true)?,
             [Some(genesis_block_hash), Some(record1)]
         );
 
@@ -56,24 +56,24 @@ fn forks() -> Result<()> {
 
         // Verify it contains the original records
         assert_eq!(
-            fork_clone.overlay.lock().unwrap().order.get(&[0, 1], true)?,
+            fork_clone.overlay.lock().unwrap().blocks.get_order(&[0, 1], true)?,
             [Some(genesis_block_hash), Some(record1)]
         );
 
         // Add another dummy record to cloned fork
-        fork_clone.overlay.lock().unwrap().order.insert(&[2], &[record2])?;
+        fork_clone.overlay.lock().unwrap().blocks.insert_order(&[2], &[record2])?;
 
         // Verify blockchain and original fork don't contain the second record
         assert_eq!(
-            blockchain.order.get(&[0, 1, 2], false)?,
+            blockchain.blocks.get_order(&[0, 1, 2], false)?,
             [Some(genesis_block_hash), None, None]
         );
         assert_eq!(
-            fork.overlay.lock().unwrap().order.get(&[0, 1, 2], false)?,
+            fork.overlay.lock().unwrap().blocks.get_order(&[0, 1, 2], false)?,
             [Some(genesis_block_hash), Some(record1), None]
         );
         assert_eq!(
-            fork_clone.overlay.lock().unwrap().order.get(&[0, 1, 2], true)?,
+            fork_clone.overlay.lock().unwrap().blocks.get_order(&[0, 1, 2], true)?,
             [Some(genesis_block_hash), Some(record1), Some(record2)]
         );
 

+ 378 - 404
src/blockchain/block_store.rs

@@ -139,30 +139,194 @@ impl BlockInfo {
     }
 }
 
-/// [`Block`] sled tree
+/// Auxiliary structure used to keep track of blocks order.
+#[derive(Debug, SerialEncodable, SerialDecodable)]
+pub struct BlockOrder {
+    /// Order number
+    pub number: u64,
+    /// Block headerhash of that number
+    pub block: blake3::Hash,
+}
+
+/// Auxiliary structure used to keep track of block ranking information.
+/// Note: we only need height cummulative ranks, but we also keep its actual
+/// ranks, so we can verify the sequence and/or know specific block height
+/// ranks, if ever needed.
+#[derive(Debug)]
+pub struct BlockRanks {
+    /// Block target rank
+    pub target_rank: BigUint,
+    /// Height cummulative targets rank
+    pub targets_rank: BigUint,
+    /// Block hash rank
+    pub hash_rank: BigUint,
+    /// Height cummulative hashes rank
+    pub hashes_rank: BigUint,
+}
+
+impl BlockRanks {
+    pub fn new(
+        target_rank: BigUint,
+        targets_rank: BigUint,
+        hash_rank: BigUint,
+        hashes_rank: BigUint,
+    ) -> Self {
+        Self { target_rank, targets_rank, hash_rank, hashes_rank }
+    }
+}
+
+// Note: Doing all the imports here as this might get obselete if
+// we implemented Encodable/Decodable for num_bigint::BigUint.
+impl darkfi_serial::Encodable for BlockRanks {
+    fn encode<S: std::io::Write>(&self, mut s: S) -> std::io::Result<usize> {
+        let mut len = 0;
+        len += self.target_rank.to_bytes_be().encode(&mut s)?;
+        len += self.targets_rank.to_bytes_be().encode(&mut s)?;
+        len += self.hash_rank.to_bytes_be().encode(&mut s)?;
+        len += self.hashes_rank.to_bytes_be().encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl darkfi_serial::Decodable for BlockRanks {
+    fn decode<D: std::io::Read>(mut d: D) -> std::io::Result<Self> {
+        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
+        let target_rank: BigUint = BigUint::from_bytes_be(&bytes);
+        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
+        let targets_rank: BigUint = BigUint::from_bytes_be(&bytes);
+        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
+        let hash_rank: BigUint = BigUint::from_bytes_be(&bytes);
+        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
+        let hashes_rank: BigUint = BigUint::from_bytes_be(&bytes);
+        let ret = Self { target_rank, targets_rank, hash_rank, hashes_rank };
+        Ok(ret)
+    }
+}
+
+/// Auxiliary structure used to keep track of block PoW difficulty information.
+/// Note: we only need height cummulative difficulty, but we also keep its actual
+/// difficulty, so we can verify the sequence and/or know specific block height
+/// difficulty, if ever needed.
+#[derive(Debug)]
+pub struct BlockDifficulty {
+    /// Block height number
+    pub height: u64,
+    /// Block creation timestamp
+    pub timestamp: Timestamp,
+    /// Height difficulty
+    pub difficulty: BigUint,
+    /// Height cummulative difficulty (total + height difficulty)
+    pub cummulative_difficulty: BigUint,
+    /// Block ranks
+    pub ranks: BlockRanks,
+}
+
+impl BlockDifficulty {
+    pub fn new(
+        height: u64,
+        timestamp: Timestamp,
+        difficulty: BigUint,
+        cummulative_difficulty: BigUint,
+        ranks: BlockRanks,
+    ) -> Self {
+        Self { height, timestamp, difficulty, cummulative_difficulty, ranks }
+    }
+
+    /// Represents the genesis block difficulty
+    pub fn genesis(timestamp: Timestamp) -> Self {
+        let ranks = BlockRanks::new(
+            BigUint::from(0u64),
+            BigUint::from(0u64),
+            BigUint::from(0u64),
+            BigUint::from(0u64),
+        );
+        BlockDifficulty::new(0, timestamp, BigUint::from(0u64), BigUint::from(0u64), ranks)
+    }
+}
+
+// Note: Doing all the imports here as this might get obselete if
+// we implemented Encodable/Decodable for num_bigint::BigUint.
+impl darkfi_serial::Encodable for BlockDifficulty {
+    fn encode<S: std::io::Write>(&self, mut s: S) -> std::io::Result<usize> {
+        let mut len = 0;
+        len += self.height.encode(&mut s)?;
+        len += self.timestamp.encode(&mut s)?;
+        len += self.difficulty.to_bytes_be().encode(&mut s)?;
+        len += self.cummulative_difficulty.to_bytes_be().encode(&mut s)?;
+        len += self.ranks.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl darkfi_serial::Decodable for BlockDifficulty {
+    fn decode<D: std::io::Read>(mut d: D) -> std::io::Result<Self> {
+        let height: u64 = darkfi_serial::Decodable::decode(&mut d)?;
+        let timestamp: Timestamp = darkfi_serial::Decodable::decode(&mut d)?;
+        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
+        let difficulty: BigUint = BigUint::from_bytes_be(&bytes);
+        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
+        let cummulative_difficulty: BigUint = BigUint::from_bytes_be(&bytes);
+        let ranks: BlockRanks = darkfi_serial::Decodable::decode(&mut d)?;
+        let ret = Self { height, timestamp, difficulty, cummulative_difficulty, ranks };
+        Ok(ret)
+    }
+}
+
 const SLED_BLOCK_TREE: &[u8] = b"_blocks";
+const SLED_BLOCK_ORDER_TREE: &[u8] = b"_block_order";
+const SLED_BLOCK_DIFFICULTY_TREE: &[u8] = b"_block_difficulty";
 
-/// The `BlockStore` is a `sled` tree storing all the blockchain's blocks
-/// where the key is the blocks' hash, and value is the serialized block.
+/// The `BlockStore` is a structure representing all `sled` trees related
+/// to storing the blockchain's blocks information.
 #[derive(Clone)]
-pub struct BlockStore(pub sled::Tree);
+pub struct BlockStore {
+    /// Main `sled` tree, storing all the blockchain's blocks, where the
+    /// key is the blocks' hash, and value is the serialized block.
+    pub main: sled::Tree,
+    /// The `sled` tree storing the order of the blockchain's blocks,
+    /// where the key is the order number, and the value is the blocks'
+    /// hash.
+    pub order: sled::Tree,
+    /// The `sled` tree storing the the difficulty information of the
+    /// blockchain's blocks, where the key is the block height number,
+    /// and the value is the blocks' hash.
+    pub difficulty: sled::Tree,
+}
 
 impl BlockStore {
     /// Opens a new or existing `BlockStore` on the given sled database.
     pub fn new(db: &sled::Db) -> Result<Self> {
-        let tree = db.open_tree(SLED_BLOCK_TREE)?;
-        Ok(Self(tree))
+        let main = db.open_tree(SLED_BLOCK_TREE)?;
+        let order = db.open_tree(SLED_BLOCK_ORDER_TREE)?;
+        let difficulty = db.open_tree(SLED_BLOCK_DIFFICULTY_TREE)?;
+        Ok(Self { main, order, difficulty })
     }
 
-    /// Insert a slice of [`Block`] into the store.
+    /// Insert a slice of [`Block`] into the store's main tree.
     pub fn insert(&self, blocks: &[Block]) -> Result<Vec<blake3::Hash>> {
         let (batch, ret) = self.insert_batch(blocks)?;
-        self.0.apply_batch(batch)?;
+        self.main.apply_batch(batch)?;
         Ok(ret)
     }
 
-    /// Generate the sled batch corresponding to an insert, so caller
-    /// can handle the write operation.
+    /// Insert a slice of `u64` and block hashes into the store's
+    /// order tree.
+    pub fn insert_order(&self, order: &[u64], hashes: &[blake3::Hash]) -> Result<()> {
+        let batch = self.insert_batch_order(order, hashes)?;
+        self.order.apply_batch(batch)?;
+        Ok(())
+    }
+
+    /// Insert a slice of [`BlockDifficulty`] into the store's
+    /// difficulty tree.
+    pub fn insert_difficulty(&self, block_difficulties: &[BlockDifficulty]) -> Result<()> {
+        let batch = self.insert_batch_difficulty(block_difficulties)?;
+        self.difficulty.apply_batch(batch)?;
+        Ok(())
+    }
+
+    /// Generate the sled batch corresponding to an insert to the main
+    /// tree, so caller can handle the write operation.
     /// The block's hash() function output is used as the key,
     /// while value is the serialized [`Block`] itself.
     /// On success, the function returns the block hashes in the same order.
@@ -179,86 +343,64 @@ impl BlockStore {
         Ok((batch, ret))
     }
 
-    /// Check if the block store contains a given block hash.
-    pub fn contains(&self, blockhash: &blake3::Hash) -> Result<bool> {
-        Ok(self.0.contains_key(blockhash.as_bytes())?)
-    }
+    /// Generate the sled batch corresponding to an insert to the order
+    /// tree, so caller can handle the write operation.
+    /// The block order number is used as the key, and the block hash is used as value.
+    pub fn insert_batch_order(
+        &self,
+        order: &[u64],
+        hashes: &[blake3::Hash],
+    ) -> Result<sled::Batch> {
+        if order.len() != hashes.len() {
+            return Err(Error::InvalidInputLengths)
+        }
 
-    /// Fetch given block hashes from the block store.
-    /// The resulting vector contains `Option`, which is `Some` if the block
-    /// 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<Vec<Option<Block>>> {
-        let mut ret = Vec::with_capacity(block_hashes.len());
+        let mut batch = sled::Batch::default();
 
-        for hash in block_hashes {
-            if let Some(found) = self.0.get(hash.as_bytes())? {
-                let block = deserialize(&found)?;
-                ret.push(Some(block));
-                continue
-            }
-            if strict {
-                let s = hash.to_hex().as_str().to_string();
-                return Err(Error::BlockNotFound(s))
-            }
-            ret.push(None);
+        for (i, number) in order.iter().enumerate() {
+            batch.insert(&number.to_be_bytes(), hashes[i].as_bytes());
         }
 
-        Ok(ret)
+        Ok(batch)
     }
 
-    /// 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<Vec<(blake3::Hash, Block)>> {
-        let mut blocks = vec![];
+    /// Generate the sled batch corresponding to an insert to the difficulty
+    /// tree, so caller can handle the write operation.
+    /// The block's height number is used as the key, while value is
+    //  the serialized [`BlockDifficulty`] itself.
+    pub fn insert_batch_difficulty(
+        &self,
+        block_difficulties: &[BlockDifficulty],
+    ) -> Result<sled::Batch> {
+        let mut batch = sled::Batch::default();
 
-        for block in self.0.iter() {
-            blocks.push(parse_record(block.unwrap())?);
+        for block_difficulty in block_difficulties {
+            batch.insert(&block_difficulty.height.to_be_bytes(), serialize(block_difficulty));
         }
 
-        Ok(blocks)
+        Ok(batch)
     }
-}
-
-/// Overlay structure over a [`BlockStore`] instance.
-pub struct BlockStoreOverlay(SledDbOverlayPtr);
 
-impl BlockStoreOverlay {
-    pub fn new(overlay: &SledDbOverlayPtr) -> Result<Self> {
-        overlay.lock().unwrap().open_tree(SLED_BLOCK_TREE)?;
-        Ok(Self(overlay.clone()))
+    /// Check if the store's main tree contains a given block hash.
+    pub fn contains(&self, blockhash: &blake3::Hash) -> Result<bool> {
+        Ok(self.main.contains_key(blockhash.as_bytes())?)
     }
 
-    /// Insert a slice of [`Block`] into the overlay.
-    /// The block's hash() function output 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<Vec<blake3::Hash>> {
-        let mut ret = Vec::with_capacity(blocks.len());
-        let mut lock = self.0.lock().unwrap();
-
-        for block in blocks {
-            let blockhash = block.hash();
-            lock.insert(SLED_BLOCK_TREE, blockhash.as_bytes(), &serialize(block))?;
-            ret.push(blockhash);
-        }
-
-        Ok(ret)
+    /// Check if the store's order tree contains a given order number.
+    pub fn contains_order(&self, number: u64) -> Result<bool> {
+        Ok(self.order.contains_key(number.to_be_bytes())?)
     }
 
-    /// Fetch given block hashes from the overlay.
+    /// Fetch given block hashes from the store's main tree.
     /// The resulting vector contains `Option`, which is `Some` if the block
-    /// was found in the overlay, 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<Vec<Option<Block>>> {
         let mut ret = Vec::with_capacity(block_hashes.len());
-        let lock = self.0.lock().unwrap();
 
         for hash in block_hashes {
-            if let Some(found) = lock.get(SLED_BLOCK_TREE, hash.as_bytes())? {
+            if let Some(found) = self.main.get(hash.as_bytes())? {
                 let block = deserialize(&found)?;
                 ret.push(Some(block));
                 continue
@@ -272,72 +414,17 @@ impl BlockStoreOverlay {
 
         Ok(ret)
     }
-}
-
-/// Auxiliary structure used to keep track of blocks order.
-#[derive(Debug, SerialEncodable, SerialDecodable)]
-pub struct BlockOrder {
-    /// Order number
-    pub number: u64,
-    /// Block headerhash of that number
-    pub block: blake3::Hash,
-}
-
-/// [`BlockOrder`] sled tree
-const SLED_BLOCK_ORDER_TREE: &[u8] = b"_block_order";
-
-/// The `BlockOrderStore` is a `sled` tree storing the order of the
-/// blockchain's blocks, where the key is the order number, and the value is
-/// the blocks' hash. [`BlockOrderStore`] can be queried with this order number.
-#[derive(Clone)]
-pub struct BlockOrderStore(pub sled::Tree);
-
-impl BlockOrderStore {
-    /// Opens a new or existing `BlockOrderStore` on the given sled database.
-    pub fn new(db: &sled::Db) -> Result<Self> {
-        let tree = db.open_tree(SLED_BLOCK_ORDER_TREE)?;
-        Ok(Self(tree))
-    }
 
-    /// 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 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<sled::Batch> {
-        if order.len() != hashes.len() {
-            return Err(Error::InvalidInputLengths)
-        }
-
-        let mut batch = sled::Batch::default();
-
-        for (i, number) in order.iter().enumerate() {
-            batch.insert(&number.to_be_bytes(), hashes[i].as_bytes());
-        }
-
-        Ok(batch)
-    }
-
-    /// Check if the block order store contains a given order number.
-    pub fn contains(&self, number: u64) -> Result<bool> {
-        Ok(self.0.contains_key(number.to_be_bytes())?)
-    }
-
-    /// Fetch given order numbers from the block order store.
+    /// Fetch given order numbers from the store's order tree.
     /// 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 order number was not found.
-    pub fn get(&self, order: &[u64], strict: bool) -> Result<Vec<Option<blake3::Hash>>> {
+    pub fn get_order(&self, order: &[u64], strict: bool) -> Result<Vec<Option<blake3::Hash>>> {
         let mut ret = Vec::with_capacity(order.len());
 
         for number in order {
-            if let Some(found) = self.0.get(number.to_be_bytes())? {
+            if let Some(found) = self.order.get(number.to_be_bytes())? {
                 let block_hash = deserialize(&found)?;
                 ret.push(Some(block_hash));
                 continue
@@ -351,18 +438,72 @@ impl BlockOrderStore {
         Ok(ret)
     }
 
-    /// 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<Vec<(u64, blake3::Hash)>> {
-        let mut order = vec![];
-
-        for record in self.0.iter() {
-            order.push(parse_u64_key_record(record.unwrap())?);
-        }
+    /// Fetch given block height numbers from the store's difficulty tree.
+    /// The resulting vector contains `Option`, which is `Some` if the block
+    /// height number was found in the block difficulties 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 height number was not found.
+    pub fn get_difficulty(
+        &self,
+        heights: &[u64],
+        strict: bool,
+    ) -> Result<Vec<Option<BlockDifficulty>>> {
+        let mut ret = Vec::with_capacity(heights.len());
 
-        Ok(order)
-    }
+        for height in heights {
+            if let Some(found) = self.difficulty.get(height.to_be_bytes())? {
+                let block_difficulty = deserialize(&found)?;
+                ret.push(Some(block_difficulty));
+                continue
+            }
+            if strict {
+                return Err(Error::BlockDifficultyNotFound(*height))
+            }
+            ret.push(None);
+        }
+
+        Ok(ret)
+    }
+
+    /// Retrieve all blocks from the store's main tree 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<Vec<(blake3::Hash, Block)>> {
+        let mut blocks = vec![];
+
+        for block in self.main.iter() {
+            blocks.push(parse_record(block.unwrap())?);
+        }
+
+        Ok(blocks)
+    }
+
+    /// Retrieve complete order from the store's order tree 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_order(&self) -> Result<Vec<(u64, blake3::Hash)>> {
+        let mut order = vec![];
+
+        for record in self.order.iter() {
+            order.push(parse_u64_key_record(record.unwrap())?);
+        }
+
+        Ok(order)
+    }
+
+    /// Retrieve all block difficulties from the store's difficulty tree in
+    /// the form of a vector containing (`height`, `difficulty`) tuples.
+    /// Be careful as this will try to load everything in memory.
+    pub fn get_all_difficulty(&self) -> Result<Vec<(u64, BlockDifficulty)>> {
+        let mut block_difficulties = vec![];
+
+        for record in self.difficulty.iter() {
+            block_difficulties.push(parse_u64_key_record(record.unwrap())?);
+        }
+
+        Ok(block_difficulties)
+    }
 
     /// 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
@@ -373,7 +514,7 @@ impl BlockOrderStore {
         let mut key = number;
         let mut counter = 0;
         while counter <= n {
-            if let Some(found) = self.0.get_gt(key.to_be_bytes())? {
+            if let Some(found) = self.order.get_gt(key.to_be_bytes())? {
                 let (number, hash) = parse_u64_key_record(found)?;
                 key = number;
                 ret.push(hash);
@@ -386,10 +527,10 @@ impl BlockOrderStore {
         Ok(ret)
     }
 
-    /// Fetch the first block hash in the tree, based on the `Ord`
+    /// Fetch the first block hash in the order tree, based on the `Ord`
     /// implementation for `Vec<u8>`.
     pub fn get_first(&self) -> Result<(u64, blake3::Hash)> {
-        let found = match self.0.first()? {
+        let found = match self.order.first()? {
             Some(s) => s,
             None => return Err(Error::BlockNumberNotFound(0)),
         };
@@ -398,39 +539,80 @@ impl BlockOrderStore {
         Ok((number, hash))
     }
 
-    /// Fetch the last block hash in the tree, based on the `Ord`
+    /// Fetch the last block hash in the order tree, based on the `Ord`
     /// implementation for `Vec<u8>`.
     pub fn get_last(&self) -> Result<(u64, blake3::Hash)> {
-        let found = self.0.last()?.unwrap();
+        let found = self.order.last()?.unwrap();
         let (number, hash) = parse_u64_key_record(found)?;
 
         Ok((number, hash))
     }
 
-    /// Retrieve records count
+    /// Fetch the last record in the difficulty tree, based on the `Ord`
+    /// implementation for `Vec<u8>`. If the tree is empty,
+    /// returns `None`.
+    pub fn get_last_difficulty(&self) -> Result<Option<BlockDifficulty>> {
+        let Some(found) = self.difficulty.last()? else { return Ok(None) };
+        let block_difficulty = deserialize(&found.1)?;
+        Ok(Some(block_difficulty))
+    }
+
+    /// Fetch the last N records from the difficulty store, in order.
+    pub fn get_last_n_difficulties(&self, n: usize) -> Result<Vec<BlockDifficulty>> {
+        // Build an iterator to retrieve last N records
+        let records = self.difficulty.iter().rev().take(n);
+        // Since the iterator grabs in right -> left order,
+        // we deserialize found records, and push them in reverse order
+        let mut last_n = vec![];
+        for record in records {
+            last_n.insert(0, deserialize(&record?.1)?);
+        }
+
+        Ok(last_n)
+    }
+
+    /// Retrieve store's order tree records count.
     pub fn len(&self) -> usize {
-        self.0.len()
+        self.order.len()
     }
 
-    /// Check if sled contains any records
+    /// Check if store's order tree contains any records.
     pub fn is_empty(&self) -> bool {
-        self.0.is_empty()
+        self.order.is_empty()
     }
 }
 
-/// Overlay structure over a [`BlockOrderStore`] instance.
-pub struct BlockOrderStoreOverlay(SledDbOverlayPtr);
+/// Overlay structure over a [`BlockStore`] instance.
+pub struct BlockStoreOverlay(SledDbOverlayPtr);
 
-impl BlockOrderStoreOverlay {
+impl BlockStoreOverlay {
     pub fn new(overlay: &SledDbOverlayPtr) -> Result<Self> {
+        overlay.lock().unwrap().open_tree(SLED_BLOCK_TREE)?;
         overlay.lock().unwrap().open_tree(SLED_BLOCK_ORDER_TREE)?;
+        overlay.lock().unwrap().open_tree(SLED_BLOCK_DIFFICULTY_TREE)?;
         Ok(Self(overlay.clone()))
     }
 
-    /// Insert a slice of `u64` and block hashes into the store. With sled, the
-    /// operation is done as a batch.
+    /// Insert a slice of [`Block`] into the overlay's main tree.
+    /// The block's hash() function output 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<Vec<blake3::Hash>> {
+        let mut ret = Vec::with_capacity(blocks.len());
+        let mut lock = self.0.lock().unwrap();
+
+        for block in blocks {
+            let blockhash = block.hash();
+            lock.insert(SLED_BLOCK_TREE, blockhash.as_bytes(), &serialize(block))?;
+            ret.push(blockhash);
+        }
+
+        Ok(ret)
+    }
+
+    /// Insert a slice of `u64` and block hashes into overlay's order tree.
     /// 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<()> {
+    pub fn insert_order(&self, order: &[u64], hashes: &[blake3::Hash]) -> Result<()> {
         if order.len() != hashes.len() {
             return Err(Error::InvalidInputLengths)
         }
@@ -444,12 +626,52 @@ impl BlockOrderStoreOverlay {
         Ok(())
     }
 
-    /// Fetch given order numbers from the overlay.
+    /// Insert a slice of [`BlockDifficulty`] into the overlay's difficulty tree.
+    pub fn insert_difficulty(&self, block_difficulties: &[BlockDifficulty]) -> Result<()> {
+        let mut lock = self.0.lock().unwrap();
+
+        for block_difficulty in block_difficulties {
+            lock.insert(
+                SLED_BLOCK_DIFFICULTY_TREE,
+                &block_difficulty.height.to_be_bytes(),
+                &serialize(block_difficulty),
+            )?;
+        }
+
+        Ok(())
+    }
+
+    /// Fetch given block hashes from the overlay's main tree.
+    /// The resulting vector contains `Option`, which is `Some` if the block
+    /// 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 block was not found.
+    pub fn get(&self, block_hashes: &[blake3::Hash], strict: bool) -> Result<Vec<Option<Block>>> {
+        let mut ret = Vec::with_capacity(block_hashes.len());
+        let lock = self.0.lock().unwrap();
+
+        for hash in block_hashes {
+            if let Some(found) = lock.get(SLED_BLOCK_TREE, hash.as_bytes())? {
+                let block = deserialize(&found)?;
+                ret.push(Some(block));
+                continue
+            }
+            if strict {
+                let s = hash.to_hex().as_str().to_string();
+                return Err(Error::BlockNotFound(s))
+            }
+            ret.push(None);
+        }
+
+        Ok(ret)
+    }
+
+    /// Fetch given order numbers from the overlay's order tree.
     /// 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 number was not found.
-    pub fn get(&self, order: &[u64], strict: bool) -> Result<Vec<Option<blake3::Hash>>> {
+    pub fn get_order(&self, order: &[u64], strict: bool) -> Result<Vec<Option<blake3::Hash>>> {
         let mut ret = Vec::with_capacity(order.len());
         let lock = self.0.lock().unwrap();
 
@@ -468,7 +690,7 @@ impl BlockOrderStoreOverlay {
         Ok(ret)
     }
 
-    /// Fetch the last block hash in the overlay, based on the `Ord`
+    /// Fetch the last block hash in the overlay's order tree, based on the `Ord`
     /// implementation for `Vec<u8>`.
     pub fn get_last(&self) -> Result<(u64, blake3::Hash)> {
         let found = match self.0.lock().unwrap().last(SLED_BLOCK_ORDER_TREE)? {
@@ -480,260 +702,12 @@ impl BlockOrderStoreOverlay {
         Ok((number, hash))
     }
 
-    /// Check if overlay contains any records
+    /// Check if overlay's order tree contains any records.
     pub fn is_empty(&self) -> Result<bool> {
         Ok(self.0.lock().unwrap().is_empty(SLED_BLOCK_ORDER_TREE)?)
     }
 }
 
-/// Auxiliary structure used to keep track of block ranking information.
-/// Note: we only need height cummulative ranks, but we also keep its actual
-/// ranks, so we can verify the sequence and/or know specific block height
-/// ranks, if ever needed.
-#[derive(Debug)]
-pub struct BlockRanks {
-    /// Block target rank
-    pub target_rank: BigUint,
-    /// Height cummulative targets rank
-    pub targets_rank: BigUint,
-    /// Block hash rank
-    pub hash_rank: BigUint,
-    /// Height cummulative hashes rank
-    pub hashes_rank: BigUint,
-}
-
-impl BlockRanks {
-    pub fn new(
-        target_rank: BigUint,
-        targets_rank: BigUint,
-        hash_rank: BigUint,
-        hashes_rank: BigUint,
-    ) -> Self {
-        Self { target_rank, targets_rank, hash_rank, hashes_rank }
-    }
-}
-
-// Note: Doing all the imports here as this might get obselete if
-// we implemented Encodable/Decodable for num_bigint::BigUint.
-impl darkfi_serial::Encodable for BlockRanks {
-    fn encode<S: std::io::Write>(&self, mut s: S) -> std::io::Result<usize> {
-        let mut len = 0;
-        len += self.target_rank.to_bytes_be().encode(&mut s)?;
-        len += self.targets_rank.to_bytes_be().encode(&mut s)?;
-        len += self.hash_rank.to_bytes_be().encode(&mut s)?;
-        len += self.hashes_rank.to_bytes_be().encode(&mut s)?;
-        Ok(len)
-    }
-}
-
-impl darkfi_serial::Decodable for BlockRanks {
-    fn decode<D: std::io::Read>(mut d: D) -> std::io::Result<Self> {
-        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
-        let target_rank: BigUint = BigUint::from_bytes_be(&bytes);
-        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
-        let targets_rank: BigUint = BigUint::from_bytes_be(&bytes);
-        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
-        let hash_rank: BigUint = BigUint::from_bytes_be(&bytes);
-        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
-        let hashes_rank: BigUint = BigUint::from_bytes_be(&bytes);
-        let ret = Self { target_rank, targets_rank, hash_rank, hashes_rank };
-        Ok(ret)
-    }
-}
-
-/// Auxiliary structure used to keep track of block PoW difficulty information.
-/// Note: we only need height cummulative difficulty, but we also keep its actual
-/// difficulty, so we can verify the sequence and/or know specific block height
-/// difficulty, if ever needed.
-#[derive(Debug)]
-pub struct BlockDifficulty {
-    /// Block height number
-    pub height: u64,
-    /// Block creation timestamp
-    pub timestamp: Timestamp,
-    /// Height difficulty
-    pub difficulty: BigUint,
-    /// Height cummulative difficulty (total + height difficulty)
-    pub cummulative_difficulty: BigUint,
-    /// Block ranks
-    pub ranks: BlockRanks,
-}
-
-impl BlockDifficulty {
-    pub fn new(
-        height: u64,
-        timestamp: Timestamp,
-        difficulty: BigUint,
-        cummulative_difficulty: BigUint,
-        ranks: BlockRanks,
-    ) -> Self {
-        Self { height, timestamp, difficulty, cummulative_difficulty, ranks }
-    }
-
-    /// Represents the genesis block difficulty
-    pub fn genesis(timestamp: Timestamp) -> Self {
-        let ranks = BlockRanks::new(
-            BigUint::from(0u64),
-            BigUint::from(0u64),
-            BigUint::from(0u64),
-            BigUint::from(0u64),
-        );
-        BlockDifficulty::new(0, timestamp, BigUint::from(0u64), BigUint::from(0u64), ranks)
-    }
-}
-
-// Note: Doing all the imports here as this might get obselete if
-// we implemented Encodable/Decodable for num_bigint::BigUint.
-impl darkfi_serial::Encodable for BlockDifficulty {
-    fn encode<S: std::io::Write>(&self, mut s: S) -> std::io::Result<usize> {
-        let mut len = 0;
-        len += self.height.encode(&mut s)?;
-        len += self.timestamp.encode(&mut s)?;
-        len += self.difficulty.to_bytes_be().encode(&mut s)?;
-        len += self.cummulative_difficulty.to_bytes_be().encode(&mut s)?;
-        len += self.ranks.encode(&mut s)?;
-        Ok(len)
-    }
-}
-
-impl darkfi_serial::Decodable for BlockDifficulty {
-    fn decode<D: std::io::Read>(mut d: D) -> std::io::Result<Self> {
-        let height: u64 = darkfi_serial::Decodable::decode(&mut d)?;
-        let timestamp: Timestamp = darkfi_serial::Decodable::decode(&mut d)?;
-        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
-        let difficulty: BigUint = BigUint::from_bytes_be(&bytes);
-        let bytes: Vec<u8> = darkfi_serial::Decodable::decode(&mut d)?;
-        let cummulative_difficulty: BigUint = BigUint::from_bytes_be(&bytes);
-        let ranks: BlockRanks = darkfi_serial::Decodable::decode(&mut d)?;
-        let ret = Self { height, timestamp, difficulty, cummulative_difficulty, ranks };
-        Ok(ret)
-    }
-}
-
-/// [`BlockDifficulty`] sled tree
-const SLED_BLOCK_DIFFICULTY_TREE: &[u8] = b"_block_difficulty";
-
-/// The `BlockDifficultyStore` is a `sled` tree storing the difficulty information
-/// of the blockchain's blocks, where the key is the block height number, and the
-/// value is the blocks' hash. [`BlockDifficultyStore`] can be queried with this
-/// height number.
-#[derive(Clone)]
-pub struct BlockDifficultyStore(pub sled::Tree);
-
-impl BlockDifficultyStore {
-    /// Opens a new or existing `BlockDifficultyStore` on the given sled database.
-    pub fn new(db: &sled::Db) -> Result<Self> {
-        let tree = db.open_tree(SLED_BLOCK_DIFFICULTY_TREE)?;
-        Ok(Self(tree))
-    }
-
-    /// Insert a slice of [`BlockDifficulty`] into the store.
-    pub fn insert(&self, block_difficulties: &[BlockDifficulty]) -> Result<()> {
-        let batch = self.insert_batch(block_difficulties)?;
-        self.0.apply_batch(batch)?;
-        Ok(())
-    }
-
-    /// Generate the sled batch corresponding to an insert, so caller
-    /// can handle the write operation.
-    /// The block's height number is used as the key, while value is
-    //  the serialized [`BlockDifficulty`] itself.
-    pub fn insert_batch(&self, block_difficulties: &[BlockDifficulty]) -> Result<sled::Batch> {
-        let mut batch = sled::Batch::default();
-
-        for block_difficulty in block_difficulties {
-            batch.insert(&block_difficulty.height.to_be_bytes(), serialize(block_difficulty));
-        }
-
-        Ok(batch)
-    }
-
-    /// Fetch given block height numbers from the block difficulties store.
-    /// The resulting vector contains `Option`, which is `Some` if the block
-    /// height number was found in the block difficulties 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 height number was not found.
-    pub fn get(&self, heights: &[u64], strict: bool) -> Result<Vec<Option<BlockDifficulty>>> {
-        let mut ret = Vec::with_capacity(heights.len());
-
-        for height in heights {
-            if let Some(found) = self.0.get(height.to_be_bytes())? {
-                let block_difficulty = deserialize(&found)?;
-                ret.push(Some(block_difficulty));
-                continue
-            }
-            if strict {
-                return Err(Error::BlockDifficultyNotFound(*height))
-            }
-            ret.push(None);
-        }
-
-        Ok(ret)
-    }
-
-    /// Fetch the last record in the tree, based on the `Ord`
-    /// implementation for `Vec<u8>`. If the tree is empty,
-    /// returns `None`.
-    pub fn get_last(&self) -> Result<Option<BlockDifficulty>> {
-        let Some(found) = self.0.last()? else { return Ok(None) };
-        let block_difficulty = deserialize(&found.1)?;
-        Ok(Some(block_difficulty))
-    }
-
-    /// Fetch the last N records from the block difficulties store, in order.
-    pub fn get_last_n(&self, n: usize) -> Result<Vec<BlockDifficulty>> {
-        // Build an iterator to retrieve last N records
-        let records = self.0.iter().rev().take(n);
-        // Since the iterator grabs in right -> left order,
-        // we deserialize found records, and push them in reverse order
-        let mut last_n = vec![];
-        for record in records {
-            last_n.insert(0, deserialize(&record?.1)?);
-        }
-
-        Ok(last_n)
-    }
-
-    /// Retrieve all blockdifficulties from the block difficulties store in
-    /// the form of a vector containing (`height`, `difficulty`) tuples.
-    /// Be careful as this will try to load everything in memory.
-    pub fn get_all(&self) -> Result<Vec<(u64, BlockDifficulty)>> {
-        let mut block_difficulties = vec![];
-
-        for record in self.0.iter() {
-            block_difficulties.push(parse_u64_key_record(record.unwrap())?);
-        }
-
-        Ok(block_difficulties)
-    }
-}
-
-/// Overlay structure over a [`BlockDifficultyStore`] instance.
-pub struct BlockDifficultyStoreOverlay(SledDbOverlayPtr);
-
-impl BlockDifficultyStoreOverlay {
-    pub fn new(overlay: &SledDbOverlayPtr) -> Result<Self> {
-        overlay.lock().unwrap().open_tree(SLED_BLOCK_DIFFICULTY_TREE)?;
-        Ok(Self(overlay.clone()))
-    }
-
-    /// Insert a slice of [`BlockDifficulty`] into the overlay.
-    pub fn insert(&self, block_difficulties: &[BlockDifficulty]) -> Result<()> {
-        let mut lock = self.0.lock().unwrap();
-
-        for block_difficulty in block_difficulties {
-            lock.insert(
-                SLED_BLOCK_DIFFICULTY_TREE,
-                &block_difficulty.height.to_be_bytes(),
-                &serialize(block_difficulty),
-            )?;
-        }
-
-        Ok(())
-    }
-}
-
 /// Auxiliary function to append a transaction to a Merkle tree.
 pub fn append_tx_to_merkle_tree(tree: &mut MerkleTree, tx: &Transaction) {
     let mut buf = [0u8; 64];

+ 21 - 62
src/blockchain/mod.rs

@@ -27,10 +27,7 @@ use crate::{tx::Transaction, util::time::Timestamp, Error, Result};
 
 /// Block related definitions and storage implementations
 pub mod block_store;
-pub use block_store::{
-    Block, BlockDifficulty, BlockDifficultyStore, BlockDifficultyStoreOverlay, BlockInfo,
-    BlockOrderStore, BlockOrderStoreOverlay, BlockStore, BlockStoreOverlay,
-};
+pub use block_store::{Block, BlockDifficulty, BlockInfo, BlockStore, BlockStoreOverlay};
 
 /// Header definition and storage implementation
 pub mod header_store;
@@ -53,10 +50,6 @@ pub struct Blockchain {
     pub headers: HeaderStore,
     /// Blocks sled tree
     pub blocks: BlockStore,
-    /// Block order sled tree
-    pub order: BlockOrderStore,
-    /// Block height difficulties sled tree,
-    pub difficulties: BlockDifficultyStore,
     /// Transactions related sled trees
     pub transactions: TxStore,
     /// Contracts related sled trees
@@ -68,20 +61,10 @@ impl Blockchain {
     pub fn new(db: &sled::Db) -> Result<Self> {
         let headers = HeaderStore::new(db)?;
         let blocks = BlockStore::new(db)?;
-        let order = BlockOrderStore::new(db)?;
-        let difficulties = BlockDifficultyStore::new(db)?;
         let transactions = TxStore::new(db)?;
         let contracts = ContractStore::new(db)?;
 
-        Ok(Self {
-            sled_db: db.clone(),
-            headers,
-            blocks,
-            order,
-            difficulties,
-            transactions,
-            contracts,
-        })
+        Ok(Self { sled_db: db.clone(), headers, blocks, transactions, contracts })
     }
 
     /// Insert a given [`BlockInfo`] into the blockchain database.
@@ -108,13 +91,13 @@ impl Blockchain {
         let (bocks_batch, block_hashes) = self.blocks.insert_batch(&[blk])?;
         let block_hash = block_hashes[0];
         let block_hash_vec = [block_hash];
-        trees.push(self.blocks.0.clone());
+        trees.push(self.blocks.main.clone());
         batches.push(bocks_batch);
 
         // Store block order
         let blocks_order_batch =
-            self.order.insert_batch(&[block.header.height], &block_hash_vec)?;
-        trees.push(self.order.0.clone());
+            self.blocks.insert_batch_order(&[block.header.height], &block_hash_vec)?;
+        trees.push(self.blocks.order.clone());
         batches.push(blocks_order_batch);
 
         // Perform an atomic transaction over the trees and apply the batches.
@@ -125,7 +108,7 @@ impl Blockchain {
 
     /// Check if the given [`BlockInfo`] is in the database and all trees.
     pub fn has_block(&self, block: &BlockInfo) -> Result<bool> {
-        let blockhash = match self.order.get(&[block.header.height], true) {
+        let blockhash = match self.blocks.get_order(&[block.header.height], true) {
             Ok(v) => v[0].unwrap(),
             Err(_) => return Ok(false),
         };
@@ -172,7 +155,7 @@ impl Blockchain {
     /// Retrieve [`BlockInfo`]s by given heights. Does not fail if any of them are not found.
     pub fn get_blocks_by_heights(&self, heights: &[u64]) -> Result<Vec<BlockInfo>> {
         debug!(target: "blockchain", "get_blocks_by_heights(): {:?}", heights);
-        let blockhashes = self.order.get(heights, false)?;
+        let blockhashes = self.blocks.get_order(heights, false)?;
 
         let mut hashes = vec![];
         for i in blockhashes.into_iter().flatten() {
@@ -185,13 +168,13 @@ impl Blockchain {
     /// Retrieve n blocks after given start block height.
     pub fn get_blocks_after(&self, height: u64, n: u64) -> Result<Vec<BlockInfo>> {
         debug!(target: "blockchain", "get_blocks_after(): {} -> {}", height, n);
-        let hashes = self.order.get_after(height, n)?;
+        let hashes = self.blocks.get_after(height, n)?;
         self.get_blocks_by_hash(&hashes)
     }
 
     /// Retrieve stored blocks count
     pub fn len(&self) -> usize {
-        self.order.len()
+        self.blocks.len()
     }
 
     /// Retrieve stored txs count
@@ -201,12 +184,12 @@ impl Blockchain {
 
     /// Check if blockchain contains any blocks
     pub fn is_empty(&self) -> bool {
-        self.order.is_empty()
+        self.blocks.is_empty()
     }
 
     /// Retrieve genesis (first) block height and hash.
     pub fn genesis(&self) -> Result<(u64, blake3::Hash)> {
-        self.order.get_first()
+        self.blocks.get_first()
     }
 
     /// Retrieve genesis (first) block info.
@@ -217,7 +200,7 @@ impl Blockchain {
 
     /// Retrieve the last block height and hash.
     pub fn last(&self) -> Result<(u64, blake3::Hash)> {
-        self.order.get_last()
+        self.blocks.get_last()
     }
 
     /// Retrieve the last block info.
@@ -229,7 +212,7 @@ impl Blockchain {
     /// Retrieve the last block difficulty. If the tree is empty,
     /// returns `BlockDifficulty::genesis` difficulty.
     pub fn last_block_difficulty(&self) -> Result<BlockDifficulty> {
-        if let Some(found) = self.difficulties.get_last()? {
+        if let Some(found) = self.blocks.get_last_difficulty()? {
             return Ok(found)
         }
 
@@ -239,7 +222,7 @@ impl Blockchain {
 
     /// Check if block order for the given height is in the database.
     pub fn has_height(&self, height: u64) -> Result<bool> {
-        let vec = match self.order.get(&[height], true) {
+        let vec = match self.blocks.get_order(&[height], true) {
             Ok(v) => v,
             Err(_) => return Ok(false),
         };
@@ -323,7 +306,7 @@ impl Blockchain {
     /// Retrieve all blocks contained in the blockchain in order.
     /// Be careful as this will try to load everything in memory.
     pub fn get_all(&self) -> Result<Vec<BlockInfo>> {
-        let order = self.order.get_all()?;
+        let order = self.blocks.get_all_order()?;
         let order: Vec<blake3::Hash> = order.iter().map(|x| x.1).collect();
         let blocks = self.get_blocks_by_hash(&order)?;
 
@@ -345,10 +328,6 @@ pub struct BlockchainOverlay {
     pub headers: HeaderStoreOverlay,
     /// Blocks overlay
     pub blocks: BlockStoreOverlay,
-    /// Block order overlay
-    pub order: BlockOrderStoreOverlay,
-    /// Block height difficulties overlay,
-    pub difficulties: BlockDifficultyStoreOverlay,
     /// Transactions overlay
     pub transactions: TxStoreOverlay,
     /// Contract overlay
@@ -361,30 +340,20 @@ impl BlockchainOverlay {
         let overlay = Arc::new(Mutex::new(sled_overlay::SledDbOverlay::new(&blockchain.sled_db)));
         let headers = HeaderStoreOverlay::new(&overlay)?;
         let blocks = BlockStoreOverlay::new(&overlay)?;
-        let order = BlockOrderStoreOverlay::new(&overlay)?;
-        let difficulties = BlockDifficultyStoreOverlay::new(&overlay)?;
         let transactions = TxStoreOverlay::new(&overlay)?;
         let contracts = ContractStoreOverlay::new(&overlay)?;
 
-        Ok(Arc::new(Mutex::new(Self {
-            overlay,
-            headers,
-            blocks,
-            order,
-            difficulties,
-            transactions,
-            contracts,
-        })))
+        Ok(Arc::new(Mutex::new(Self { overlay, headers, blocks, transactions, contracts })))
     }
 
     /// Check if blockchain contains any blocks
     pub fn is_empty(&self) -> Result<bool> {
-        self.order.is_empty()
+        self.blocks.is_empty()
     }
 
     /// Retrieve the last block height and hash.
     pub fn last(&self) -> Result<(u64, blake3::Hash)> {
-        self.order.get_last()
+        self.blocks.get_last()
     }
 
     /// Retrieve the last block info.
@@ -424,14 +393,14 @@ impl BlockchainOverlay {
         let block_hash_vec = [block_hash];
 
         // Store block order
-        self.order.insert(&[block.header.height], &block_hash_vec)?;
+        self.blocks.insert_order(&[block.header.height], &block_hash_vec)?;
 
         Ok(block_hash)
     }
 
     /// Check if the given [`BlockInfo`] is in the database and all trees.
     pub fn has_block(&self, block: &BlockInfo) -> Result<bool> {
-        let blockhash = match self.order.get(&[block.header.height], true) {
+        let blockhash = match self.blocks.get_order(&[block.header.height], true) {
             Ok(v) => v[0].unwrap(),
             Err(_) => return Ok(false),
         };
@@ -504,20 +473,10 @@ impl BlockchainOverlay {
         let overlay = Arc::new(Mutex::new(self.overlay.lock().unwrap().clone()));
         let headers = HeaderStoreOverlay::new(&overlay)?;
         let blocks = BlockStoreOverlay::new(&overlay)?;
-        let order = BlockOrderStoreOverlay::new(&overlay)?;
-        let difficulties = BlockDifficultyStoreOverlay::new(&overlay)?;
         let transactions = TxStoreOverlay::new(&overlay)?;
         let contracts = ContractStoreOverlay::new(&overlay)?;
 
-        Ok(Arc::new(Mutex::new(Self {
-            overlay,
-            headers,
-            blocks,
-            order,
-            difficulties,
-            transactions,
-            contracts,
-        })))
+        Ok(Arc::new(Mutex::new(Self { overlay, headers, blocks, transactions, contracts })))
     }
 }
 

+ 2 - 2
src/validator/pow.rs

@@ -99,7 +99,7 @@ impl PoWModule {
         let mut timestamps = RingBuffer::<Timestamp, BUF_SIZE>::new();
         let mut difficulties = RingBuffer::<BigUint, BUF_SIZE>::new();
         let mut cummulative_difficulty = BigUint::zero();
-        let last_n = blockchain.difficulties.get_last_n(BUF_SIZE)?;
+        let last_n = blockchain.blocks.get_last_n_difficulties(BUF_SIZE)?;
         for difficulty in last_n {
             timestamps.push(difficulty.timestamp);
             difficulties.push(difficulty.cummulative_difficulty.clone());
@@ -285,7 +285,7 @@ impl PoWModule {
         difficulty: BlockDifficulty,
     ) -> Result<()> {
         self.append(difficulty.timestamp, &difficulty.difficulty);
-        overlay.lock().unwrap().difficulties.insert(&[difficulty])
+        overlay.lock().unwrap().blocks.insert_difficulty(&[difficulty])
     }
 
     /// Mine provided block, based on next mine target

+ 1 - 1
src/validator/verification.rs

@@ -155,7 +155,7 @@ pub fn validate_blockchain(
     // Generate a PoW module
     let mut module = PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty)?;
     // We use block order store here so we have all blocks in order
-    let blocks = blockchain.order.get_all()?;
+    let blocks = blockchain.blocks.get_all_order()?;
     for (index, block) in blocks[1..].iter().enumerate() {
         let full_blocks = blockchain.get_blocks_by_hash(&[blocks[index].1, block.1])?;
         let full_block = &full_blocks[1];