فهرست منبع

script/research/dark-forest: indexes integrity check added

aggstam 2 سال پیش
والد
کامیت
95b9caf1c4

+ 1 - 0
script/research/dark-forest/Cargo.toml

@@ -10,3 +10,4 @@ edition = "2021"
 [workspace]
 
 [dependencies]
+thiserror = "1.0.50"

+ 33 - 0
script/research/dark-forest/src/error.rs

@@ -0,0 +1,33 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/// Main result type used by this library.
+pub type DarkTreeResult<T> = std::result::Result<T, DarkTreeError>;
+
+/// General library errors.
+#[derive(Debug, Clone, thiserror::Error)]
+pub enum DarkTreeError {
+    #[error("Invalid DarkLeaf index found: {0} (Expected: {1}")]
+    InvalidLeafIndex(usize, usize),
+
+    #[error("Invalid DarkLeaf parent index found for leaf: {0}")]
+    InvalidLeafParentIndex(usize),
+
+    #[error("Invalid DarkLeaf children index found for leaf: {0}")]
+    InvalidLeafChildrenIndexes(usize),
+}

+ 44 - 0
script/research/dark-forest/src/lib.rs

@@ -18,6 +18,10 @@
 
 use std::{collections::VecDeque, iter::FusedIterator, mem};
 
+/// Error handling
+mod error;
+use error::{DarkTreeError, DarkTreeResult};
+
 #[cfg(test)]
 mod tests;
 
@@ -118,6 +122,46 @@ impl<T> DarkTree<T> {
         self.set_parent_children_indexes(None);
     }
 
+    /// Verify [`DarkTree`]'s leaf parent and children indexes validity,
+    /// and trigger the check of its children indexes
+    fn check_parent_children_indexes(&self, parent_index: Option<usize>) -> DarkTreeResult<()> {
+        // Check our leafs parent index
+        if self.leaf.parent_index != parent_index {
+            return Err(DarkTreeError::InvalidLeafParentIndex(self.leaf.index))
+        }
+
+        // Now recursively, we check nodes children indexes and keep
+        // their index in our own children index list
+        let mut children_indexes = vec![];
+        for child in &self.children {
+            child.check_parent_children_indexes(Some(self.leaf.index))?;
+            children_indexes.push(child.leaf.index);
+        }
+
+        // Check our leafs children indexes
+        if self.leaf.children_indexes != children_indexes {
+            return Err(DarkTreeError::InvalidLeafChildrenIndexes(self.leaf.index))
+        }
+
+        Ok(())
+    }
+
+    /// Verify current [`DarkTree`]'s leafs indexes validity,
+    /// based on DFS post-order traversal order. This call
+    /// assumes it was triggered for the root of the tree,
+    /// which has no parent index.
+    fn integrity_check(&self) -> DarkTreeResult<()> {
+        // First we check each leaf index
+        for (index, leaf) in self.iter().enumerate() {
+            if index != leaf.index {
+                return Err(DarkTreeError::InvalidLeafIndex(leaf.index, index))
+            }
+        }
+
+        // Now we trigger recursion to check each nodes rest indexes
+        self.check_parent_children_indexes(None)
+    }
+
     /// Immutably iterate through the tree, using DFS post-order
     /// traversal.
     fn iter(&self) -> DarkTreeIter<'_, T> {

+ 19 - 9
script/research/dark-forest/src/tests.rs

@@ -16,7 +16,7 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use crate::{DarkLeaf, DarkTree};
+use crate::{DarkLeaf, DarkTree, DarkTreeResult};
 
 /// Gereate a predefined [`DarkTree`] along with its
 /// expected traversal order.
@@ -31,7 +31,7 @@ use crate::{DarkLeaf, DarkTree};
 ///   0  1  3   5 7   8  11      15  16       19
 ///
 /// Expected traversal order is indicated by each leaf's number
-fn generate_tree() -> (DarkTree<i32>, Vec<i32>) {
+fn generate_tree() -> DarkTreeResult<(DarkTree<i32>, Vec<i32>)> {
     let mut tree = DarkTree::new(
         22,
         vec![
@@ -60,15 +60,16 @@ fn generate_tree() -> (DarkTree<i32>, Vec<i32>) {
     );
 
     tree.index();
+    tree.integrity_check()?;
 
     let traversal_order = (0..23).collect();
 
-    (tree, traversal_order)
+    Ok((tree, traversal_order))
 }
 
 #[test]
-pub fn test_darktree_iterator() {
-    let (tree, traversal_order) = generate_tree();
+pub fn test_darktree_iterator() -> DarkTreeResult<()> {
+    let (tree, traversal_order) = generate_tree()?;
 
     // Use [`DarkTree`] iterator to collect current
     // data, in order
@@ -82,11 +83,14 @@ pub fn test_darktree_iterator() {
     // data from it, returns the expected one, as per
     // expected traversal order.
     assert_eq!(tree.iter().nth(1).unwrap().data, traversal_order[1]);
+
+    // Thanks for reading
+    Ok(())
 }
 
 #[test]
-fn test_darktree_traversal_order() {
-    let (mut tree, traversal_order) = generate_tree();
+fn test_darktree_traversal_order() -> DarkTreeResult<()> {
+    let (mut tree, traversal_order) = generate_tree()?;
 
     // Loop using the fusion immutable iterator,
     // verifying we grab the correct [`DarkLeaf`]
@@ -131,11 +135,14 @@ fn test_darktree_traversal_order() {
     for (index, leaf) in tree.into_iter().enumerate() {
         assert_eq!(leaf.data, traversal_order[index]);
     }
+
+    // Thanks for reading
+    Ok(())
 }
 
 #[test]
-fn test_darktree_mut_iterator() {
-    let (mut tree, _) = generate_tree();
+fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
+    let (mut tree, _) = generate_tree()?;
 
     // Loop using [`DarkTree`] .iter_mut() mutable
     // iterator, grabing a mutable reference over a
@@ -377,4 +384,7 @@ fn test_darktree_mut_iterator() {
     // Verify iterator collected the data in the expected
     // traversal order.
     assert_eq!(nums, traversal_order);
+
+    // Thanks for reading
+    Ok(())
 }