mirror of
https://github.com/zaphar/merkle-dag.git
synced 2025-07-22 02:29:49 -04:00
Node comparison within a given DAG.
This commit is contained in:
parent
3d50dda7f8
commit
3f2ddf308b
58
src/lib.rs
58
src/lib.rs
@ -19,12 +19,18 @@ use node::Node;
|
||||
mod hash;
|
||||
mod node;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum NodeCompare {
|
||||
After,
|
||||
Before,
|
||||
Equivalent,
|
||||
Uncomparable,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EdgeError {
|
||||
NoSuchDependents,
|
||||
}
|
||||
// TODO(jwall): In order to avoid copies it is probably smart to have some concept of
|
||||
// a node pool.
|
||||
|
||||
/// A Merkle-DAG implementation. This is a modification on the standard Merkle Tree data structure
|
||||
/// but instead of a tree it is a DAG and as a result can have multiple roots. A merkle-dag specifies
|
||||
@ -98,7 +104,53 @@ where
|
||||
&self.nodes
|
||||
}
|
||||
|
||||
// TODO(jwall): How to specify a partial ordering for nodes in a graph?
|
||||
/// Compare two nodes by id in the graph. If the left id is an ancestor of the right node
|
||||
/// then `returns `NodeCompare::Before`. If the right id is an ancestor of the left node
|
||||
/// then returns `NodeCompare::After`. If both id's are equal then the returns
|
||||
/// `NodeCompare::Equivalent`. If neither id are parts of the same subgraph then returns
|
||||
/// `NodeCompare::Uncomparable`.
|
||||
pub fn compare(&self, left: &[u8; HASH_LEN], right: &[u8; HASH_LEN]) -> NodeCompare {
|
||||
if left == right {
|
||||
NodeCompare::Equivalent
|
||||
} else {
|
||||
// Is left node an ancestor of right node?
|
||||
if self.search_graph(right, left) {
|
||||
NodeCompare::Before
|
||||
// is right node an ancestor of left node?
|
||||
} else if self.search_graph(left, right) {
|
||||
NodeCompare::After
|
||||
} else {
|
||||
NodeCompare::Uncomparable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn search_graph(&self, root_id: &[u8; HASH_LEN], search_id: &[u8; HASH_LEN]) -> bool {
|
||||
if root_id == search_id {
|
||||
return true;
|
||||
}
|
||||
let root_node = match self.get_node_by_id(root_id) {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let mut stack = vec![root_node];
|
||||
while !stack.is_empty() {
|
||||
let node = stack.pop().unwrap();
|
||||
let deps = node.dependency_ids();
|
||||
for dep in deps {
|
||||
if search_id == dep {
|
||||
return true;
|
||||
}
|
||||
stack.push(match self.get_node_by_id(dep) {
|
||||
Some(n) => n,
|
||||
None => panic!("Invalid DAG STATE encountered"),
|
||||
})
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, HW, const HASH_LEN: usize> Default for DAG<N, HW, HASH_LEN>
|
||||
|
@ -19,7 +19,6 @@ use crate::DAG;
|
||||
fn edge_strategy(nodes_count: usize) -> impl Strategy<Value = (Vec<String>, BTreeSet<usize>)> {
|
||||
prop::collection::vec(".*", 4..nodes_count).prop_flat_map(|payloads| {
|
||||
let nodes_len = payloads.len();
|
||||
// TODO(jwall): Generate valid DAGs
|
||||
// select a random set of payloads to be roots.
|
||||
// select a random set of non root payloads to be dependencies
|
||||
(
|
||||
|
70
src/test.rs
70
src/test.rs
@ -83,3 +83,73 @@ fn test_adding_nodes_is_idempotent_regardless_of_dep_order() {
|
||||
assert_eq!(root_size, dag.get_roots().len());
|
||||
assert_eq!(nodes_size, dag.get_nodes().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_comparison_equivalent() {
|
||||
let mut dag = DAG::<&str, DefaultHasher, 8>::new();
|
||||
let quake_node_id = dag.add_node("quake", BTreeSet::new()).unwrap();
|
||||
assert_eq!(
|
||||
dag.compare(&quake_node_id, &quake_node_id),
|
||||
NodeCompare::Equivalent
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_comparison_before() {
|
||||
let mut dag = DAG::<&str, DefaultHasher, 8>::new();
|
||||
let quake_node_id = dag.add_node("quake", BTreeSet::new()).unwrap();
|
||||
let qualm_node_id = dag
|
||||
.add_node("qualm", BTreeSet::from([quake_node_id.clone()]))
|
||||
.unwrap();
|
||||
let quell_node_id = dag
|
||||
.add_node("quell", BTreeSet::from([qualm_node_id.clone()]))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
dag.compare(&quake_node_id, &qualm_node_id),
|
||||
NodeCompare::Before
|
||||
);
|
||||
assert_eq!(
|
||||
dag.compare(&quake_node_id, &quell_node_id),
|
||||
NodeCompare::Before
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_comparison_after() {
|
||||
let mut dag = DAG::<&str, DefaultHasher, 8>::new();
|
||||
let quake_node_id = dag.add_node("quake", BTreeSet::new()).unwrap();
|
||||
let qualm_node_id = dag
|
||||
.add_node("qualm", BTreeSet::from([quake_node_id.clone()]))
|
||||
.unwrap();
|
||||
let quell_node_id = dag
|
||||
.add_node("quell", BTreeSet::from([qualm_node_id.clone()]))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
dag.compare(&qualm_node_id, &quake_node_id),
|
||||
NodeCompare::After
|
||||
);
|
||||
assert_eq!(
|
||||
dag.compare(&quell_node_id, &quake_node_id),
|
||||
NodeCompare::After
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_comparison_no_shared_graph() {
|
||||
let mut dag = DAG::<&str, DefaultHasher, 8>::new();
|
||||
let quake_node_id = dag.add_node("quake", BTreeSet::new()).unwrap();
|
||||
let qualm_node_id = dag.add_node("qualm", BTreeSet::new()).unwrap();
|
||||
let quell_node_id = dag.add_node("quell", BTreeSet::new()).unwrap();
|
||||
assert_eq!(
|
||||
dag.compare(&qualm_node_id, &quake_node_id),
|
||||
NodeCompare::Uncomparable
|
||||
);
|
||||
assert_eq!(
|
||||
dag.compare(&quell_node_id, &quake_node_id),
|
||||
NodeCompare::Uncomparable
|
||||
);
|
||||
assert_eq!(
|
||||
dag.compare(&quell_node_id, &qualm_node_id),
|
||||
NodeCompare::Uncomparable
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user