1use std::cmp::Ordering;
2use std::collections::HashMap;
3use tofuri_core::*;
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct Branch {
6 pub hash: Hash,
7 pub height: usize,
8 pub timestamp: u32,
9}
10impl Branch {
11 fn new(hash: Hash, height: usize, timestamp: u32) -> Branch {
12 Branch { hash, height, timestamp }
13 }
14}
15#[derive(Default, Debug, Clone)]
16pub struct Tree {
17 branches: Vec<Branch>,
18 hashes: HashMap<Hash, Hash>,
19}
20impl Tree {
21 pub fn main(&self) -> Option<&Branch> {
22 self.branches.first()
23 }
24 pub fn size(&self) -> usize {
25 self.hashes.len()
26 }
27 pub fn hashes(&self, trust_fork_after_blocks: usize) -> (Vec<Hash>, Vec<Hash>) {
28 let mut trusted = vec![];
29 if let Some(main) = self.main() {
30 let mut hash = main.hash;
31 loop {
32 trusted.push(hash);
33 match self.get(&hash) {
34 Some(previous_hash) => hash = *previous_hash,
35 None => break,
36 };
37 }
38 }
39 if let Some(hash) = trusted.last() {
40 if hash != &[0; 32] {
41 panic!("broken chain")
42 }
43 trusted.pop();
44 }
45 trusted.reverse();
46 let len = trusted.len();
47 let start = if len < trust_fork_after_blocks { 0 } else { len - trust_fork_after_blocks };
48 let dynamic = trusted.drain(start..len).collect();
49 (trusted, dynamic)
50 }
51 pub fn hashes_dynamic(&self, trust_fork_after_blocks: usize) -> Vec<Hash> {
52 let mut vec = vec![];
53 if let Some(main) = self.main() {
54 let mut hash = main.hash;
55 for _ in 0..trust_fork_after_blocks {
56 vec.push(hash);
57 match self.get(&hash) {
58 Some(previous_hash) => hash = *previous_hash,
59 None => break,
60 };
61 }
62 }
63 if let Some(hash) = vec.last() {
64 if hash == &[0; 32] {
65 vec.pop();
66 }
67 }
68 vec.reverse();
69 vec
70 }
71 pub fn get(&self, hash: &Hash) -> Option<&Hash> {
72 self.hashes.get(hash)
73 }
74 pub fn insert(&mut self, hash: Hash, previous_hash: Hash, timestamp: u32) -> Option<bool> {
75 if self.hashes.insert(hash, previous_hash).is_some() {
76 return None;
77 }
78 if let Some(index) = self.branches.iter().position(|a| a.hash == previous_hash) {
79 self.branches[index] = Branch::new(hash, self.branches[index].height + 1, timestamp);
81 Some(false)
82 } else {
83 self.branches.push(Branch::new(hash, self.height(&previous_hash), timestamp));
85 Some(true)
86 }
87 }
88 pub fn sort_branches(&mut self) {
89 self.branches.sort_by(|a, b| match b.height.cmp(&a.height) {
90 Ordering::Equal => a.timestamp.cmp(&b.timestamp),
91 x => x,
92 });
93 }
94 pub fn clear(&mut self) {
95 self.branches.clear();
96 self.hashes.clear();
97 }
98 fn height(&self, previous_hash: &Hash) -> usize {
99 let mut hash = previous_hash;
100 let mut height = 0;
101 loop {
102 match self.hashes.get(hash) {
103 Some(previous_hash) => {
104 hash = previous_hash;
105 height += 1;
106 }
107 None => {
108 if hash != &[0; 32] {
109 panic!("broken chain")
110 }
111 break;
112 }
113 };
114 }
115 height
116 }
117}
118#[cfg(test)]
119mod tests {
120 use super::*;
121 #[test]
122 fn test() {
123 let mut tree = Tree::default();
124 tree.insert([0x11; 32], [0x00; 32], 1);
125 tree.insert([0x22; 32], [0x11; 32], 1);
126 tree.insert([0x33; 32], [0x22; 32], 1);
127 assert_eq!(tree.size(), 3);
128 tree.insert([0x44; 32], [0x33; 32], 1);
129 tree.insert([0x55; 32], [0x22; 32], 1);
130 tree.insert([0x66; 32], [0x00; 32], 1);
131 tree.insert([0x77; 32], [0x55; 32], 0);
132 assert_eq!(tree.main(), Some(&Branch::new([0x44; 32], 3, 1)));
133 tree.sort_branches();
134 assert_eq!(tree.main(), Some(&Branch::new([0x77; 32], 3, 0)));
135 assert_eq!(tree.size(), 7);
136 }
137}