finality_grandpa/
vote_graph.rs

1// Copyright 2018-2019 Parity Technologies (UK) Ltd
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Maintains the vote-graph of the blockchain.
16//!
17//! See docs on `VoteGraph` for more information.
18
19use 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	// ancestor hashes in reverse order, e.g. ancestors[0] is the parent
32	// and the last entry is the hash of the parent vote-node.
33	ancestors: Vec<H>,
34	descendents: Vec<H>, // descendent vote-nodes
35	cumulative_vote: V,
36}
37
38impl<H: Ord + PartialEq + Clone, N: BlockNumberOps, V> Entry<H, N, V> {
39	// whether the given hash, number pair is a direct ancestor of this node.
40	// `None` signifies that the graph must be traversed further back.
41	fn in_direct_ancestry(&self, hash: &H, number: N) -> Option<bool> {
42		self.ancestor_block(number).map(|h| h == hash)
43	}
44
45	// Get ancestor block by number. Returns `None` if there is no block
46	// by that number in the direct ancestry.
47	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	// get ancestor vote-node.
57	fn ancestor_node(&self) -> Option<H> {
58		self.ancestors.last().cloned()
59	}
60}
61
62// a subchain of blocks by hash.
63struct Subchain<H, N> {
64	hashes: Vec<H>, // forward order.
65	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
74/// Maintains a DAG of blocks in the chain which have votes attached to them,
75/// and vote data which is accumulated along edges.
76pub 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	/// Create a new `VoteGraph` with base node as given.
90	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	/// Get the base block.
109	pub fn base(&self) -> (H, N) {
110		(self.base.clone(), self.base_number)
111	}
112
113	/// Adjust the base of the graph. The new base must be an ancestor of the
114	/// old base.
115	///
116	/// Provide an ancestry proof from the old base to the new. The proof
117	/// should be in reverse order from the old base's parent.
118	pub fn adjust_base(&mut self, ancestry_proof: &[H]) {
119		let new_hash = match ancestry_proof.last() {
120			None => return, // empty -- nothing to do.
121			Some(h) => h,
122		};
123
124		// not a valid ancestry proof. TODO: error?
125		if ancestry_proof.len() > self.base_number.as_() {
126			return
127		}
128
129		// hack because we can't convert usize -> N, only vice-versa.
130		// hopefully LLVM can optimize.
131		//
132		// TODO: Add TryFrom to `BlockNumberOps`.
133		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	/// Insert a vote with given value into the graph at given hash and number.
161	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			// this entry already exists
179		}
180
181		// update cumulative vote data.
182		// NOTE: below this point, there always exists a node with the given hash and number.
183		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	/// Find the block with the highest block number in the chain with the given head
202	/// which fulfills the given condition.
203	///
204	/// Returns `None` if the given head is not in the graph or no node fulfills the
205	/// given condition.
206	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					// The block has a vote-node in the graph.
214					let node =
215						self.entries.get(&hash).expect("by defn of find_containing_nodes; qed");
216					// If the weight is sufficient, we are done.
217					if condition(&node.cumulative_vote) {
218						return Some((hash, number))
219					}
220					// Not enough weight, check the parent block.
221					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 there are no vote-nodes below the block in the graph,
231					// the block is not in the graph at all.
232					if children.is_empty() {
233						return None
234					}
235					// The block is "contained" in the graph (i.e. in the ancestry-chain
236					// of at least one vote-node) but does not itself have a vote-node.
237					// Check if the accumulated weight on all child vote-nodes is sufficient.
238					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					// Not enough weight, check the parent block.
248					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, // Reached base without sufficient weight.
253						Some(parent) => {
254							hash = parent.clone();
255							number = number - N::one();
256						},
257					}
258				},
259			}
260		}
261	}
262
263	/// Find the total vote on a given block.
264	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	/// Find the best GHOST descendent of the given block.
286	/// Pass a closure used to evaluate the cumulative vote value.
287	///
288	/// The GHOST (hash, number) returned will be the block with highest number for which the
289	/// cumulative votes of descendents and itself causes the closure to evaluate to true.
290	///
291	/// This assumes that the evaluation closure is one which returns true for at most a single
292	/// descendent of a block, in that only one fork of a block can be "heavy"
293	/// enough to trigger the threshold.
294	///
295	/// Returns `None` when the given `current_best` does not fulfill the condition.
296	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		// breadth-first search starting from this node.
329		loop {
330			let next_descendent = active_node
331				.descendents
332				.iter()
333				.map(|d| (d.clone(), get_node(d)))
334				.filter(|&(_, node)| {
335					// take only descendents with our block in the ancestry.
336					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					// once we've made at least one hop, we don't need to constrain
347					// ancestry anymore.
348					force_constrain = false;
349					node_key = key;
350					active_node = node;
351				},
352				None => break,
353			}
354		}
355
356		// active_node and node_key now correspond to the vote-node with enough cumulative votes.
357		// its descendents comprise frontier of vote-nodes which individually don't have enough votes
358		// to pass the threshold but some subset of them join either at `active_node`'s block or at some
359		// descendent block of it, giving that block sufficient votes.
360		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	// given a key, node pair (which must correspond), assuming this node fulfills the condition,
370	// this function will find the highest point at which its descendents merge, which may be the
371	// node itself.
372	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		// TODO: for long ranges of blocks this could get inefficient
401		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	// attempts to find the containing node keys for the given hash and number.
440	//
441	// returns `None` if there is a node by that key already, and a vector
442	// (potentially empty) of nodes with the given block in its ancestor-edge
443	// otherwise.
444	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		// iterate vote-heads and their ancestry backwards until we find the one with
453		// this target hash in that chain.
454		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 node has been checked already, break
464				if !visited.insert(head.clone()) {
465					break
466				}
467
468				match active_entry.in_direct_ancestry(&hash, number) {
469					Some(true) => {
470						// set containing node and continue search.
471						containing_keys.push(head.clone());
472					},
473					Some(false) => {}, // nothing in this branch. continue search.
474					None =>
475						if let Some(prev) = active_entry.ancestor_node() {
476							head = prev;
477							continue // iterate backwards
478						},
479				}
480
481				break
482			}
483		}
484
485		Some(containing_keys)
486	}
487
488	// introduce a branch to given vote-nodes.
489	//
490	// `descendents` is a list of nodes with ancestor-edges containing the given ancestor.
491	//
492	// This function panics if any member of `descendents` is not a vote-node
493	// or does not have ancestor with given hash and number OR if `ancestor_hash`
494	// is already a known entry.
495	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			// example: splitting number 10 at ancestor 4
505			// before: [9 8 7 6 5 4 3 2 1]
506			// after: [9 8 7 6 5 4], [3 2 1]
507			// we ensure the `entry.ancestors` is drained regardless of whether
508			// the `new_entry` has already been constructed.
509			{
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	// append a vote-node onto the chain-tree. This should only be called if
555	// no node in the tree keeps the target anyway.
556	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()); // ancestry doesn't include base.
559
560		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		// introduce a branch in the middle.
723		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		// Inserting the Bs first used to exhibit incorrect behaviour.
844		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		// `actual` used to (incorrectly) be (genesis, 0)
851		assert_eq!(actual, ("A", 1));
852	}
853}