1use crate::std::{
20 collections::{BTreeMap, BTreeSet},
21 fmt::Debug,
22 ops::AddAssign,
23 vec::Vec,
24};
25
26use super::{BlockNumberOps, Chain, Error};
27
28#[cfg_attr(any(feature = "std", test), derive(Debug))]
29struct Entry<H, N, V> {
30 number: N,
31 ancestors: Vec<H>,
34 descendents: Vec<H>, cumulative_vote: V,
36}
37
38impl<H: Ord + PartialEq + Clone, N: BlockNumberOps, V> Entry<H, N, V> {
39 fn in_direct_ancestry(&self, hash: &H, number: N) -> Option<bool> {
42 self.ancestor_block(number).map(|h| h == hash)
43 }
44
45 fn ancestor_block(&self, number: N) -> Option<&H> {
48 if number >= self.number {
49 return None
50 }
51 let offset = self.number - number - N::one();
52
53 self.ancestors.get(offset.as_())
54 }
55
56 fn ancestor_node(&self) -> Option<H> {
58 self.ancestors.last().cloned()
59 }
60}
61
62struct Subchain<H, N> {
64 hashes: Vec<H>, best_number: N,
66}
67
68impl<H: Clone, N: Copy + BlockNumberOps> Subchain<H, N> {
69 fn best(&self) -> Option<(H, N)> {
70 self.hashes.last().map(|x| (x.clone(), self.best_number))
71 }
72}
73
74pub struct VoteGraph<H: Ord + Eq, N, V> {
77 entries: BTreeMap<H, Entry<H, N, V>>,
78 heads: BTreeSet<H>,
79 base: H,
80 base_number: N,
81}
82
83impl<H, N, V> VoteGraph<H, N, V>
84where
85 H: Eq + Clone + Ord + Debug,
86 V: for<'a> AddAssign<&'a V> + Default + Clone + Debug,
87 N: Copy + Debug + BlockNumberOps,
88{
89 pub fn new(base_hash: H, base_number: N, base_node: V) -> Self {
91 let mut entries = BTreeMap::new();
92 entries.insert(
93 base_hash.clone(),
94 Entry {
95 number: base_number,
96 ancestors: Vec::new(),
97 descendents: Vec::new(),
98 cumulative_vote: base_node,
99 },
100 );
101
102 let mut heads = BTreeSet::new();
103 heads.insert(base_hash.clone());
104
105 VoteGraph { entries, heads, base: base_hash, base_number }
106 }
107
108 pub fn base(&self) -> (H, N) {
110 (self.base.clone(), self.base_number)
111 }
112
113 pub fn adjust_base(&mut self, ancestry_proof: &[H]) {
119 let new_hash = match ancestry_proof.last() {
120 None => return, Some(h) => h,
122 };
123
124 if ancestry_proof.len() > self.base_number.as_() {
126 return
127 }
128
129 let new_number = {
134 let mut new_number = self.base_number;
135 for _ in 0..ancestry_proof.len() {
136 new_number = new_number - N::one();
137 }
138 new_number
139 };
140
141 let entry = {
142 let old_entry =
143 self.entries.get_mut(&self.base).expect("base hash entry always exists; qed");
144
145 old_entry.ancestors.extend(ancestry_proof.iter().cloned());
146
147 Entry {
148 number: new_number,
149 ancestors: Vec::new(),
150 descendents: vec![self.base.clone()],
151 cumulative_vote: old_entry.cumulative_vote.clone(),
152 }
153 };
154
155 self.entries.insert(new_hash.clone(), entry);
156 self.base = new_hash.clone();
157 self.base_number = new_number;
158 }
159
160 pub fn insert<C: Chain<H, N>, W>(
162 &mut self,
163 hash: H,
164 number: N,
165 vote: W,
166 chain: &C,
167 ) -> Result<(), Error>
168 where
169 V: for<'a> AddAssign<&'a W>,
170 {
171 if let Some(containing) = self.find_containing_nodes(hash.clone(), number) {
172 if containing.is_empty() {
173 self.append(hash.clone(), number, chain)?;
174 } else {
175 self.introduce_branch(containing, hash.clone(), number);
176 }
177 } else {
178 }
180
181 let mut inspecting_hash = hash;
184 loop {
185 let active_entry = self
186 .entries
187 .get_mut(&inspecting_hash)
188 .expect("vote-node and its ancestry always exist after initial phase; qed");
189
190 active_entry.cumulative_vote += &vote;
191
192 match active_entry.ancestor_node() {
193 Some(parent) => inspecting_hash = parent,
194 None => break,
195 }
196 }
197
198 Ok(())
199 }
200
201 pub fn find_ancestor<F>(&self, mut hash: H, mut number: N, condition: F) -> Option<(H, N)>
207 where
208 F: Fn(&V) -> bool,
209 {
210 loop {
211 match self.find_containing_nodes(hash.clone(), number) {
212 None => {
213 let node =
215 self.entries.get(&hash).expect("by defn of find_containing_nodes; qed");
216 if condition(&node.cumulative_vote) {
218 return Some((hash, number))
219 }
220 match node.ancestors.get(0) {
222 None => return None,
223 Some(a) => {
224 hash = a.clone();
225 number = node.number - N::one();
226 },
227 }
228 },
229 Some(children) => {
230 if children.is_empty() {
233 return None
234 }
235 let mut v = V::default();
239 for c in &children {
240 let e = self.entries.get(c).expect("all children in graph; qed");
241 v += &e.cumulative_vote;
242 }
243 if condition(&v) {
244 return Some((hash, number))
245 }
246
247 let child = children.last().expect("children not empty; qed");
249 let entry = self.entries.get(child).expect("all children in graph; qed");
250 let offset = (entry.number - number).as_();
251 match entry.ancestors.get(offset) {
252 None => return None, Some(parent) => {
254 hash = parent.clone();
255 number = number - N::one();
256 },
257 }
258 },
259 }
260 }
261 }
262
263 pub fn cumulative_vote<'a>(&'a self, hash: H, number: N) -> V {
265 let entries = &self.entries;
266 let get_node = |hash: &_| -> &'a _ {
267 entries
268 .get(hash)
269 .expect("node either base or referenced by other in graph; qed")
270 };
271
272 match self.find_containing_nodes(hash.clone(), number) {
273 None => get_node(&hash).cumulative_vote.clone(),
274 Some(nodes) => {
275 let mut v = Default::default();
276 for node in nodes {
277 v += &get_node(&node).cumulative_vote;
278 }
279
280 v
281 },
282 }
283 }
284
285 pub fn find_ghost<'a, F>(&'a self, current_best: Option<(H, N)>, condition: F) -> Option<(H, N)>
297 where
298 F: Fn(&V) -> bool,
299 {
300 let entries = &self.entries;
301 let get_node = |hash: &_| -> &'a _ {
302 entries
303 .get(hash)
304 .expect("node either base or referenced by other in graph; qed")
305 };
306
307 let (mut node_key, mut force_constrain) = current_best
308 .clone()
309 .and_then(|(hash, number)| match self.find_containing_nodes(hash.clone(), number) {
310 None => Some((hash, false)),
311 Some(ref x) if !x.is_empty() => {
312 let ancestor = get_node(&x[0])
313 .ancestor_node()
314 .expect("node containing non-node in history always has ancestor; qed");
315
316 Some((ancestor, true))
317 },
318 Some(_) => None,
319 })
320 .unwrap_or_else(|| (self.base.clone(), false));
321
322 let mut active_node = get_node(&node_key);
323
324 if !condition(&active_node.cumulative_vote) {
325 return None
326 }
327
328 loop {
330 let next_descendent = active_node
331 .descendents
332 .iter()
333 .map(|d| (d.clone(), get_node(d)))
334 .filter(|&(_, node)| {
335 if let (true, Some(&(ref h, n))) = (force_constrain, current_best.as_ref()) {
337 node.in_direct_ancestry(h, n).unwrap_or(false)
338 } else {
339 true
340 }
341 })
342 .find(|&(_, node)| condition(&node.cumulative_vote));
343
344 match next_descendent {
345 Some((key, node)) => {
346 force_constrain = false;
349 node_key = key;
350 active_node = node;
351 },
352 None => break,
353 }
354 }
355
356 self.ghost_find_merge_point(
361 node_key,
362 active_node,
363 if force_constrain { current_best } else { None },
364 condition,
365 )
366 .best()
367 }
368
369 fn ghost_find_merge_point<'a, F>(
373 &'a self,
374 node_key: H,
375 active_node: &'a Entry<H, N, V>,
376 force_constrain: Option<(H, N)>,
377 condition: F,
378 ) -> Subchain<H, N>
379 where
380 F: Fn(&V) -> bool,
381 {
382 let mut descendent_nodes: Vec<_> = active_node
383 .descendents
384 .iter()
385 .map(|h| self.entries.get(h).expect("descendents always present in node storage; qed"))
386 .filter(|n| {
387 if let Some((ref h, num)) = force_constrain {
388 n.in_direct_ancestry(h, num).unwrap_or(false)
389 } else {
390 true
391 }
392 })
393 .collect();
394
395 let base_number = active_node.number;
396 let mut best_number = active_node.number;
397 let mut descendent_blocks = Vec::with_capacity(descendent_nodes.len());
398 let mut hashes = vec![node_key];
399
400 let mut offset = N::zero();
402 loop {
403 offset = offset + N::one();
404
405 let mut new_best = None;
406 for d_node in &descendent_nodes {
407 if let Some(d_block) = d_node.ancestor_block(base_number + offset) {
408 match descendent_blocks.binary_search_by_key(&d_block, |(x, _)| x) {
409 Ok(idx) => {
410 descendent_blocks[idx].1 += &d_node.cumulative_vote;
411 if condition(&descendent_blocks[idx].1) {
412 new_best = Some(d_block.clone());
413 break
414 }
415 },
416 Err(idx) => descendent_blocks
417 .insert(idx, (d_block.clone(), d_node.cumulative_vote.clone())),
418 }
419 }
420 }
421
422 match new_best {
423 Some(new_best) => {
424 best_number = best_number + N::one();
425
426 descendent_blocks.clear();
427 descendent_nodes
428 .retain(|n| n.in_direct_ancestry(&new_best, best_number).unwrap_or(false));
429
430 hashes.push(new_best);
431 },
432 None => break,
433 }
434 }
435
436 Subchain { hashes, best_number }
437 }
438
439 fn find_containing_nodes(&self, hash: H, number: N) -> Option<Vec<H>> {
445 if self.entries.contains_key(&hash) {
446 return None
447 }
448
449 let mut containing_keys = Vec::new();
450 let mut visited = BTreeSet::new();
451
452 for mut head in self.heads.iter().cloned() {
455 let mut active_entry;
456
457 loop {
458 active_entry = match self.entries.get(&head) {
459 Some(e) => e,
460 None => break,
461 };
462
463 if !visited.insert(head.clone()) {
465 break
466 }
467
468 match active_entry.in_direct_ancestry(&hash, number) {
469 Some(true) => {
470 containing_keys.push(head.clone());
472 },
473 Some(false) => {}, None =>
475 if let Some(prev) = active_entry.ancestor_node() {
476 head = prev;
477 continue },
479 }
480
481 break
482 }
483 }
484
485 Some(containing_keys)
486 }
487
488 fn introduce_branch(&mut self, descendents: Vec<H>, ancestor_hash: H, ancestor_number: N) {
496 let produced_entry = descendents.into_iter().fold(None, |mut maybe_entry, descendent| {
497 let entry = self
498 .entries
499 .get_mut(&descendent)
500 .expect("this function only invoked with keys of vote-nodes; qed");
501
502 debug_assert!(entry.in_direct_ancestry(&ancestor_hash, ancestor_number).unwrap());
503
504 {
510 let prev_ancestor = entry.ancestor_node();
511 let offset_usize: usize = if ancestor_number > entry.number {
512 panic!("this function only invoked with direct ancestors; qed")
513 } else {
514 (entry.number - ancestor_number).as_()
515 };
516 let new_ancestors = entry.ancestors.drain(offset_usize..);
517
518 let &mut (ref mut new_entry, _) = maybe_entry.get_or_insert_with(move || {
519 let new_entry = Entry {
520 number: ancestor_number,
521 ancestors: new_ancestors.collect(),
522 descendents: vec![],
523 cumulative_vote: V::default(),
524 };
525
526 (new_entry, prev_ancestor)
527 });
528
529 new_entry.descendents.push(descendent);
530 new_entry.cumulative_vote += &entry.cumulative_vote;
531 }
532
533 maybe_entry
534 });
535
536 if let Some((new_entry, prev_ancestor)) = produced_entry {
537 if let Some(prev_ancestor) = prev_ancestor {
538 let prev_ancestor_node = self
539 .entries
540 .get_mut(&prev_ancestor)
541 .expect("Prior ancestor is referenced from a node; qed");
542
543 prev_ancestor_node.descendents.retain(|h| !new_entry.descendents.contains(h));
544 prev_ancestor_node.descendents.push(ancestor_hash.clone());
545 }
546
547 assert!(
548 self.entries.insert(ancestor_hash, new_entry).is_none(),
549 "this function is only invoked when there is no entry for the ancestor already; qed",
550 )
551 }
552 }
553
554 fn append<C: Chain<H, N>>(&mut self, hash: H, number: N, chain: &C) -> Result<(), Error> {
557 let mut ancestry = chain.ancestry(self.base.clone(), hash.clone())?;
558 ancestry.push(self.base.clone()); let mut ancestor_index = None;
561 for (i, ancestor) in ancestry.iter().enumerate() {
562 if let Some(entry) = self.entries.get_mut(ancestor) {
563 entry.descendents.push(hash.clone());
564 ancestor_index = Some(i);
565 break
566 }
567 }
568
569 let ancestor_index = ancestor_index.expect(
570 "base is kept; \
571 chain returns ancestry only if the block is a descendent of base; qed",
572 );
573
574 let ancestor_hash = ancestry[ancestor_index].clone();
575 ancestry.truncate(ancestor_index + 1);
576
577 self.entries.insert(
578 hash.clone(),
579 Entry {
580 number,
581 ancestors: ancestry,
582 descendents: Vec::new(),
583 cumulative_vote: V::default(),
584 },
585 );
586
587 self.heads.remove(&ancestor_hash);
588 self.heads.insert(hash);
589
590 Ok(())
591 }
592}
593
594#[cfg(test)]
595mod tests {
596 use super::*;
597 use crate::testing::chain::{DummyChain, GENESIS_HASH};
598
599 #[test]
600 fn graph_fork_not_at_node() {
601 let mut chain = DummyChain::new();
602 let mut tracker = VoteGraph::new(GENESIS_HASH, 1, 0u32);
603
604 chain.push_blocks(GENESIS_HASH, &["A", "B", "C"]);
605 chain.push_blocks("C", &["D1", "E1", "F1"]);
606 chain.push_blocks("C", &["D2", "E2", "F2"]);
607
608 tracker.insert("A", 2, 100, &chain).unwrap();
609 tracker.insert("E1", 6, 100, &chain).unwrap();
610 tracker.insert("F2", 7, 100, &chain).unwrap();
611
612 assert!(tracker.heads.contains("E1"));
613 assert!(tracker.heads.contains("F2"));
614 assert!(!tracker.heads.contains("A"));
615
616 let a_entry = tracker.entries.get("A").unwrap();
617 assert_eq!(a_entry.descendents, vec!["E1", "F2"]);
618 assert_eq!(a_entry.cumulative_vote, 300);
619
620 let e_entry = tracker.entries.get("E1").unwrap();
621 assert_eq!(e_entry.ancestor_node().unwrap(), "A");
622 assert_eq!(e_entry.cumulative_vote, 100);
623
624 let f_entry = tracker.entries.get("F2").unwrap();
625 assert_eq!(f_entry.ancestor_node().unwrap(), "A");
626 assert_eq!(f_entry.cumulative_vote, 100);
627 }
628
629 #[test]
630 fn graph_fork_at_node() {
631 let mut chain = DummyChain::new();
632 let mut tracker1 = VoteGraph::new(GENESIS_HASH, 1, 0u32);
633 let mut tracker2 = VoteGraph::new(GENESIS_HASH, 1, 0u32);
634
635 chain.push_blocks(GENESIS_HASH, &["A", "B", "C"]);
636 chain.push_blocks("C", &["D1", "E1", "F1"]);
637 chain.push_blocks("C", &["D2", "E2", "F2"]);
638
639 tracker1.insert("C", 4, 100, &chain).unwrap();
640 tracker1.insert("E1", 6, 100, &chain).unwrap();
641 tracker1.insert("F2", 7, 100, &chain).unwrap();
642
643 tracker2.insert("E1", 6, 100, &chain).unwrap();
644 tracker2.insert("F2", 7, 100, &chain).unwrap();
645 tracker2.insert("C", 4, 100, &chain).unwrap();
646
647 for tracker in &[&tracker1, &tracker2] {
648 assert!(tracker.heads.contains("E1"));
649 assert!(tracker.heads.contains("F2"));
650 assert!(!tracker.heads.contains("C"));
651
652 let c_entry = tracker.entries.get("C").unwrap();
653 assert!(c_entry.descendents.contains(&"E1"));
654 assert!(c_entry.descendents.contains(&"F2"));
655 assert_eq!(c_entry.ancestor_node().unwrap(), GENESIS_HASH);
656 assert_eq!(c_entry.cumulative_vote, 300);
657
658 let e_entry = tracker.entries.get("E1").unwrap();
659 assert_eq!(e_entry.ancestor_node().unwrap(), "C");
660 assert_eq!(e_entry.cumulative_vote, 100);
661
662 let f_entry = tracker.entries.get("F2").unwrap();
663 assert_eq!(f_entry.ancestor_node().unwrap(), "C");
664 assert_eq!(f_entry.cumulative_vote, 100);
665 }
666 }
667
668 #[test]
669 fn ghost_merge_at_node() {
670 let mut chain = DummyChain::new();
671 let mut tracker = VoteGraph::new(GENESIS_HASH, 1, 0u32);
672
673 chain.push_blocks(GENESIS_HASH, &["A", "B", "C"]);
674 chain.push_blocks("C", &["D1", "E1", "F1"]);
675 chain.push_blocks("C", &["D2", "E2", "F2"]);
676
677 tracker.insert("B", 3, 0, &chain).unwrap();
678 tracker.insert("C", 4, 100, &chain).unwrap();
679 tracker.insert("E1", 6, 100, &chain).unwrap();
680 tracker.insert("F2", 7, 100, &chain).unwrap();
681
682 assert_eq!(tracker.find_ghost(None, |&x| x >= 250), Some(("C", 4)));
683 assert_eq!(tracker.find_ghost(Some(("C", 4)), |&x| x >= 250), Some(("C", 4)));
684 assert_eq!(tracker.find_ghost(Some(("B", 3)), |&x| x >= 250), Some(("C", 4)));
685 }
686
687 #[test]
688 fn ghost_merge_not_at_node_one_side_weighted() {
689 let mut chain = DummyChain::new();
690 let mut tracker = VoteGraph::new(GENESIS_HASH, 1, 0u32);
691
692 chain.push_blocks(GENESIS_HASH, &["A", "B", "C", "D", "E", "F"]);
693 chain.push_blocks("F", &["G1", "H1", "I1"]);
694 chain.push_blocks("F", &["G2", "H2", "I2"]);
695
696 tracker.insert("B", 3, 0, &chain).unwrap();
697 tracker.insert("G1", 8, 100, &chain).unwrap();
698 tracker.insert("H2", 9, 150, &chain).unwrap();
699
700 assert_eq!(tracker.find_ghost(None, |&x| x >= 250), Some(("F", 7)));
701 assert_eq!(tracker.find_ghost(Some(("F", 7)), |&x| x >= 250), Some(("F", 7)));
702 assert_eq!(tracker.find_ghost(Some(("C", 4)), |&x| x >= 250), Some(("F", 7)));
703 assert_eq!(tracker.find_ghost(Some(("B", 3)), |&x| x >= 250), Some(("F", 7)));
704 }
705
706 #[test]
707 fn ghost_introduce_branch() {
708 let mut chain = DummyChain::new();
709 let mut tracker = VoteGraph::new(GENESIS_HASH, 1, 0u32);
710
711 chain.push_blocks(GENESIS_HASH, &["A", "B", "C", "D", "E", "F"]);
712 chain.push_blocks("E", &["EA", "EB", "EC", "ED"]);
713 chain.push_blocks("F", &["FA", "FB", "FC"]);
714
715 tracker.insert("FC", 10, 5, &chain).unwrap();
716 tracker.insert("ED", 10, 7, &chain).unwrap();
717
718 assert_eq!(tracker.find_ghost(None, |&x| x >= 10), Some(("E", 6)));
719
720 assert_eq!(tracker.entries.get(GENESIS_HASH).unwrap().descendents, vec!["FC", "ED"]);
721
722 tracker.insert("E", 6, 3, &chain).unwrap();
724
725 assert_eq!(tracker.entries.get(GENESIS_HASH).unwrap().descendents, vec!["E"]);
726 let descendents = &tracker.entries.get("E").unwrap().descendents;
727 assert_eq!(descendents.len(), 2);
728 assert!(descendents.contains(&"ED"));
729 assert!(descendents.contains(&"FC"));
730
731 assert_eq!(tracker.find_ghost(None, |&x| x >= 10), Some(("E", 6)));
732 assert_eq!(tracker.find_ghost(Some(("C", 4)), |&x| x >= 10), Some(("E", 6)));
733 assert_eq!(tracker.find_ghost(Some(("E", 6)), |&x| x >= 10), Some(("E", 6)));
734 }
735
736 #[test]
737 fn walk_back_from_block_in_edge_fork_below() {
738 let mut chain = DummyChain::new();
739 let mut tracker = VoteGraph::new(GENESIS_HASH, 1, 0u32);
740
741 chain.push_blocks(GENESIS_HASH, &["A", "B", "C"]);
742 chain.push_blocks("C", &["D1", "E1", "F1", "G1", "H1", "I1"]);
743 chain.push_blocks("C", &["D2", "E2", "F2", "G2", "H2", "I2"]);
744
745 tracker.insert("B", 3, 10, &chain).unwrap();
746 tracker.insert("F1", 7, 5, &chain).unwrap();
747 tracker.insert("G2", 8, 5, &chain).unwrap();
748
749 let test_cases = &["D1", "D2", "E1", "E2", "F1", "F2", "G2"];
750
751 for block in test_cases {
752 let number = chain.number(block);
753 assert_eq!(tracker.find_ancestor(block, number, |&x| x > 5).unwrap(), ("C", 4));
754 }
755 }
756
757 #[test]
758 fn walk_back_from_fork_block_node_below() {
759 let mut chain = DummyChain::new();
760 let mut tracker = VoteGraph::new(GENESIS_HASH, 1, 0u32);
761
762 chain.push_blocks(GENESIS_HASH, &["A", "B", "C", "D"]);
763 chain.push_blocks("D", &["E1", "F1", "G1", "H1", "I1"]);
764 chain.push_blocks("D", &["E2", "F2", "G2", "H2", "I2"]);
765
766 tracker.insert("B", 3, 10, &chain).unwrap();
767 tracker.insert("F1", 7, 5, &chain).unwrap();
768 tracker.insert("G2", 8, 5, &chain).unwrap();
769
770 assert_eq!(tracker.find_ancestor("G2", 8, |&x| x > 5).unwrap(), ("D", 5));
771 let test_cases = &["E1", "E2", "F1", "F2", "G2"];
772
773 for block in test_cases {
774 let number = chain.number(block);
775 assert_eq!(tracker.find_ancestor(block, number, |&x| x > 5).unwrap(), ("D", 5));
776 }
777 }
778
779 #[test]
780 fn walk_back_at_node() {
781 let mut chain = DummyChain::new();
782 let mut tracker = VoteGraph::new(GENESIS_HASH, 1, 0u32);
783
784 chain.push_blocks(GENESIS_HASH, &["A", "B", "C"]);
785 chain.push_blocks("C", &["D1", "E1", "F1", "G1", "H1", "I1"]);
786 chain.push_blocks("C", &["D2", "E2", "F2"]);
787
788 tracker.insert("C", 4, 10, &chain).unwrap();
789 tracker.insert("F1", 7, 5, &chain).unwrap();
790 tracker.insert("F2", 7, 5, &chain).unwrap();
791 tracker.insert("I1", 10, 1, &chain).unwrap();
792
793 let test_cases = &["C", "D1", "D2", "E1", "E2", "F1", "F2", "I1"];
794
795 for block in test_cases {
796 let number = chain.number(block);
797 assert_eq!(tracker.find_ancestor(block, number, |&x| x >= 20).unwrap(), ("C", 4));
798 }
799 }
800
801 #[test]
802 fn adjust_base() {
803 let mut chain = DummyChain::new();
804 let mut tracker = VoteGraph::new("E", 6, 0u32);
805
806 chain.push_blocks(GENESIS_HASH, &["A", "B", "C", "D", "E", "F"]);
807 chain.push_blocks("E", &["EA", "EB", "EC", "ED"]);
808 chain.push_blocks("F", &["FA", "FB", "FC"]);
809
810 tracker.insert("FC", 10, 5, &chain).unwrap();
811 tracker.insert("ED", 10, 7, &chain).unwrap();
812
813 assert_eq!(tracker.base(), ("E", 6));
814
815 tracker.adjust_base(&["D", "C", "B", "A"]);
816
817 assert_eq!(tracker.base(), ("A", 2));
818
819 chain.push_blocks("A", &["3", "4", "5"]);
820
821 tracker.adjust_base(&[GENESIS_HASH]);
822 assert_eq!(tracker.base(), (GENESIS_HASH, 1));
823
824 assert_eq!(tracker.entries.get(GENESIS_HASH).unwrap().cumulative_vote, 12);
825
826 tracker.insert("5", 5, 3, &chain).unwrap();
827
828 assert_eq!(tracker.entries.get(GENESIS_HASH).unwrap().cumulative_vote, 15);
829 }
830
831 #[test]
832 fn find_ancestor_is_largest() {
833 let mut chain = DummyChain::new();
834 let mut tracker = VoteGraph::new(GENESIS_HASH, 0, 0);
835
836 chain.push_blocks(GENESIS_HASH, &["A"]);
837 chain.push_blocks(GENESIS_HASH, &["B"]);
838 chain.push_blocks("A", &["A1"]);
839 chain.push_blocks("A", &["A2"]);
840 chain.push_blocks("B", &["B1"]);
841 chain.push_blocks("B", &["B2"]);
842
843 tracker.insert("B1", 2, 1, &chain).unwrap();
845 tracker.insert("B2", 2, 1, &chain).unwrap();
846 tracker.insert("A1", 2, 1, &chain).unwrap();
847 tracker.insert("A2", 2, 1, &chain).unwrap();
848
849 let actual = tracker.find_ancestor("A", 1, |x| x >= &2).unwrap();
850 assert_eq!(actual, ("A", 1));
852 }
853}