mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
bin/ircd: mvc: update root
This commit is contained in:
@@ -22,6 +22,12 @@ use darkfi::{
|
||||
Result,
|
||||
};
|
||||
|
||||
// TODO
|
||||
// Pass EventId for all the functions instead of EventNodePtr
|
||||
// Use hashmap for Event's childrens
|
||||
// Remove Mutex from Event's childrens
|
||||
// More tests
|
||||
|
||||
type EventId = [u8; 32];
|
||||
|
||||
const MAX_DEPTH: u32 = 10;
|
||||
@@ -145,6 +151,7 @@ impl Model {
|
||||
|
||||
// clean up the tree from old eventnodes
|
||||
self.prune_forks().await;
|
||||
self.update_root().await;
|
||||
|
||||
// Parent does not yet exist
|
||||
if !self.event_map.contains_key(&prev_event) {
|
||||
@@ -179,7 +186,7 @@ impl Model {
|
||||
|
||||
async fn prune_forks(&mut self) {
|
||||
let head = self.find_head().await;
|
||||
let head_event_hash = head.event.hash();
|
||||
let head_hash = head.event.hash();
|
||||
for (event_hash, node) in self.event_map.clone() {
|
||||
// to prevent running through the same node twice
|
||||
if !self.event_map.contains_key(&event_hash) {
|
||||
@@ -187,12 +194,12 @@ impl Model {
|
||||
}
|
||||
|
||||
// skip the head event
|
||||
if event_hash == head_event_hash {
|
||||
if event_hash == head_hash {
|
||||
continue
|
||||
}
|
||||
|
||||
let empty_children = node.children.lock().await.is_empty();
|
||||
if empty_children {
|
||||
// check if the node is a leaf
|
||||
if node.children.lock().await.is_empty() {
|
||||
let depth = self.diff_depth(node.clone(), self.find_head().await);
|
||||
if depth > MAX_DEPTH {
|
||||
self.remove_node(node.clone()).await;
|
||||
@@ -201,22 +208,85 @@ impl Model {
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_root(&mut self) {
|
||||
let head = self.find_head().await;
|
||||
let head_hash = head.event.hash();
|
||||
|
||||
// collect the leaves in the tree
|
||||
let mut leaves = vec![];
|
||||
|
||||
for (event_hash, node) in self.event_map.clone() {
|
||||
// skip the head event
|
||||
if event_hash == head_hash {
|
||||
continue
|
||||
}
|
||||
|
||||
// check if the node is a leaf
|
||||
if node.children.lock().await.is_empty() {
|
||||
leaves.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
// find the common ancestor between each leaf and the head event
|
||||
let mut ancestors = vec![];
|
||||
for leaf in leaves {
|
||||
let ancestor = self.find_ancestor(leaf, head.clone());
|
||||
let ancestor = self.event_map.get(&ancestor).unwrap().clone();
|
||||
ancestors.push(ancestor);
|
||||
}
|
||||
|
||||
// find the highest ancestor
|
||||
let highest_ancestor = ancestors.iter().max_by(|&a, &b| {
|
||||
self.find_depth(a.clone(), head_hash).cmp(&self.find_depth(b.clone(), head_hash))
|
||||
});
|
||||
|
||||
// set the new root
|
||||
if let Some(ancestor) = highest_ancestor {
|
||||
let ancestor_hash = ancestor.event.hash();
|
||||
|
||||
// the ancestor must have at least height > 10
|
||||
let ancestor_height = self.find_height(self.get_root(), ancestor_hash).await.unwrap();
|
||||
if ancestor_height < 10 {
|
||||
return
|
||||
}
|
||||
|
||||
// removing the parents of the new root node
|
||||
let mut root = self.get_root();
|
||||
loop {
|
||||
let root_hash = root.event.hash();
|
||||
|
||||
if root_hash == ancestor_hash {
|
||||
break
|
||||
}
|
||||
|
||||
let root_childs = root.children.lock().await;
|
||||
assert_eq!(root_childs.len(), 1);
|
||||
|
||||
let child = root_childs.get(0).unwrap().clone();
|
||||
drop(root_childs);
|
||||
|
||||
self.event_map.remove(&root_hash);
|
||||
root = child;
|
||||
}
|
||||
|
||||
self.current_root = ancestor_hash;
|
||||
}
|
||||
}
|
||||
|
||||
async fn remove_node(&mut self, mut node: EventNodePtr) {
|
||||
loop {
|
||||
let event_id = node.event.hash();
|
||||
let parent_event_id = node.parent.as_ref().unwrap().event.hash();
|
||||
|
||||
self.event_map.remove(&event_id);
|
||||
|
||||
let parent_node = self.event_map.get_mut(&parent_event_id).unwrap();
|
||||
let children = &mut parent_node.children.lock().await;
|
||||
let index = children.iter().position(|n| n.event.hash() == event_id).unwrap();
|
||||
children.remove(index);
|
||||
let parent = node.parent.as_ref().unwrap().clone();
|
||||
let parent_children = &mut parent.children.lock().await;
|
||||
let index = parent_children.iter().position(|n| n.event.hash() == event_id).unwrap();
|
||||
parent_children.remove(index);
|
||||
|
||||
if !children.is_empty() {
|
||||
if !parent_children.is_empty() {
|
||||
return
|
||||
}
|
||||
node = parent_node.clone()
|
||||
node = parent.clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,16 +334,42 @@ impl Model {
|
||||
(current_node.expect("internal logic error"), current_max)
|
||||
}
|
||||
|
||||
// TODO change this to count from bottom
|
||||
fn find_depth(&self, mut node: EventNodePtr, ancestor_id: EventId) -> u32 {
|
||||
let mut depth = 0;
|
||||
while node.event.hash() != ancestor_id {
|
||||
depth += 1;
|
||||
node = node.parent.as_ref().expect("non-root nodes should have a parent set").clone();
|
||||
if let Some(parent) = node.parent.clone() {
|
||||
node = parent
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
depth
|
||||
}
|
||||
|
||||
#[async_recursion]
|
||||
async fn find_height(&self, parent: EventNodePtr, child_id: EventId) -> Option<u32> {
|
||||
let mut height = 0;
|
||||
if parent.event.hash() == child_id {
|
||||
return Some(height)
|
||||
}
|
||||
|
||||
height += 1;
|
||||
|
||||
let children = parent.children.lock().await.clone();
|
||||
|
||||
if children.is_empty() {
|
||||
return None
|
||||
}
|
||||
|
||||
for parent_child in children.iter() {
|
||||
if let Some(h) = self.find_height(parent_child.clone(), child_id).await {
|
||||
return Some(height + h)
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn find_ancestor(&self, mut node_a: EventNodePtr, mut node_b: EventNodePtr) -> EventId {
|
||||
// node_a is a child of node_b
|
||||
let is_child = node_b.event.hash() == node_a.parent.as_ref().unwrap().event.hash();
|
||||
@@ -411,6 +507,84 @@ async fn realmain(_settings: Args, _executor: Arc<Executor<'_>>) -> Result<()> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_update_root() {
|
||||
let mut model = Model::new();
|
||||
let root_id = model.get_root().event.hash();
|
||||
|
||||
// event_node 1
|
||||
// Fill this node with 5 events
|
||||
let mut id1 = root_id;
|
||||
for x in 0..5 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id1, &format!("chain 1 msg {}", x), "message", timestamp);
|
||||
id1 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
|
||||
// event_node 2
|
||||
// Fill this node with 14 events
|
||||
let mut id2 = root_id;
|
||||
for x in 0..14 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id2, &format!("chain 2 msg {}", x), "message", timestamp);
|
||||
id2 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
|
||||
// Fill id2 node with 8 events
|
||||
let mut id3 = id2;
|
||||
for x in 14..22 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id3, &format!("chain 2 msg {}", x), "message", timestamp);
|
||||
id3 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
|
||||
// Fill id2 node with 9 events
|
||||
let mut id4 = id2;
|
||||
for x in 14..23 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id4, &format!("chain 2 msg {}", x), "message", timestamp);
|
||||
id4 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
|
||||
assert_eq!(model.find_height(model.get_root(), id2).await.unwrap(), 0);
|
||||
assert_eq!(model.find_height(model.get_root(), id3).await.unwrap(), 8);
|
||||
assert_eq!(model.find_height(model.get_root(), id4).await.unwrap(), 9);
|
||||
assert_eq!(model.current_root, id2);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_find_height() {
|
||||
let mut model = Model::new();
|
||||
let root_id = model.get_root().event.hash();
|
||||
|
||||
// event_node 1
|
||||
// Fill this node with 8 events
|
||||
let mut id1 = root_id;
|
||||
for x in 0..8 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id1, &format!("chain 1 msg {}", x), "message", timestamp);
|
||||
id1 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
|
||||
// event_node 2
|
||||
// Fill this node with 14 events
|
||||
let mut id2 = root_id;
|
||||
for x in 0..14 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id2, &format!("chain 2 msg {}", x), "message", timestamp);
|
||||
id2 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
|
||||
assert_eq!(model.find_height(model.get_root(), id1).await.unwrap(), 8);
|
||||
assert_eq!(model.find_height(model.get_root(), id2).await.unwrap(), 14);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_prune_forks() {
|
||||
let mut model = Model::new();
|
||||
@@ -422,7 +596,7 @@ mod tests {
|
||||
let mut id1 = root_id;
|
||||
for x in 0..3 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id1, &format!("alice {}", x), "alice message", timestamp);
|
||||
let node = create_message(id1, &format!("chain 1 msg {}", x), "message", timestamp);
|
||||
id1 = node.hash();
|
||||
model.add(node).await;
|
||||
event_node_1_ids.push(id1);
|
||||
@@ -434,7 +608,7 @@ mod tests {
|
||||
let mut id2 = root_id;
|
||||
for x in 0..14 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id2, &format!("bob {}", x), "bob message", timestamp);
|
||||
let node = create_message(id2, &format!("chain 2 msg {}", x), "message", timestamp);
|
||||
id2 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
@@ -458,7 +632,7 @@ mod tests {
|
||||
let mut id1 = root_id;
|
||||
for x in 0..7 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id1, &format!("alice {}", x), "alice message", timestamp);
|
||||
let node = create_message(id1, &format!("chain 1 msg {}", x), "message", timestamp);
|
||||
id1 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
@@ -470,7 +644,7 @@ mod tests {
|
||||
let mut id2 = root_id;
|
||||
for x in 0..14 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id2, &format!("bob {}", x), "bob message", timestamp);
|
||||
let node = create_message(id2, &format!("chain 2 msg {}", x), "message", timestamp);
|
||||
id2 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
@@ -483,7 +657,7 @@ mod tests {
|
||||
let mut id3 = root_id;
|
||||
for x in 0..3 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id3, &format!("phi {}", x), "phi message", timestamp);
|
||||
let node = create_message(id3, &format!("chain 3 msg {}", x), "message", timestamp);
|
||||
id3 = node.hash();
|
||||
model.add(node).await;
|
||||
|
||||
@@ -497,7 +671,7 @@ mod tests {
|
||||
// At the end this fork must overtake the event_node 2
|
||||
for x in 7..14 {
|
||||
let timestamp = get_current_time() + 1;
|
||||
let node = create_message(id1, &format!("alice {}", x), "alice message", timestamp);
|
||||
let node = create_message(id1, &format!("chain 1 msg {}", x), "message", timestamp);
|
||||
id1 = node.hash();
|
||||
model.add(node).await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user