Skip to main content

sc_consensus_epochs/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Generic utilities for epoch-based consensus engines.
20
21pub mod migration;
22
23use codec::{Decode, Encode};
24use fork_tree::{FilterAction, ForkTree};
25use sc_client_api::utils::is_descendent_of;
26use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata};
27use sp_runtime::traits::{Block as BlockT, NumberFor, One, Zero};
28use std::{
29	borrow::{Borrow, BorrowMut},
30	collections::BTreeMap,
31	ops::{Add, Sub},
32};
33
34/// A builder for `is_descendent_of` functions.
35pub trait IsDescendentOfBuilder<Hash> {
36	/// The error returned by the function.
37	type Error: std::error::Error;
38	/// A function that can tell you if the second parameter is a descendent of
39	/// the first.
40	type IsDescendentOf: Fn(&Hash, &Hash) -> Result<bool, Self::Error>;
41
42	/// Build an `is_descendent_of` function.
43	///
44	/// The `current` parameter can be `Some` with the details a fresh block whose
45	/// details aren't yet stored, but its parent is.
46	///
47	/// The format of `current` when `Some` is `(current, current_parent)`.
48	fn build_is_descendent_of(&self, current: Option<(Hash, Hash)>) -> Self::IsDescendentOf;
49}
50
51/// Produce a descendent query object given the client.
52pub fn descendent_query<H, Block>(client: &H) -> HeaderBackendDescendentBuilder<&H, Block> {
53	HeaderBackendDescendentBuilder(client, std::marker::PhantomData)
54}
55
56/// Wrapper to get around unconstrained type errors when implementing
57/// `IsDescendentOfBuilder` for header backends.
58pub struct HeaderBackendDescendentBuilder<H, Block>(H, std::marker::PhantomData<Block>);
59
60impl<'a, H, Block> IsDescendentOfBuilder<Block::Hash>
61	for HeaderBackendDescendentBuilder<&'a H, Block>
62where
63	H: HeaderBackend<Block> + HeaderMetadata<Block, Error = ClientError>,
64	Block: BlockT,
65{
66	type Error = ClientError;
67	type IsDescendentOf = Box<dyn Fn(&Block::Hash, &Block::Hash) -> Result<bool, ClientError> + 'a>;
68
69	fn build_is_descendent_of(
70		&self,
71		current: Option<(Block::Hash, Block::Hash)>,
72	) -> Self::IsDescendentOf {
73		Box::new(is_descendent_of(self.0, current))
74	}
75}
76
77/// Epoch data, distinguish whether it is genesis or not.
78///
79/// Once an epoch is created, it must have a known `start_slot` and `end_slot`, which cannot be
80/// changed. Consensus engine may modify any other data in the epoch, if needed.
81pub trait Epoch: std::fmt::Debug {
82	/// Descriptor for the next epoch.
83	type NextEpochDescriptor;
84	/// Type of the slot number.
85	type Slot: Ord + Copy + std::fmt::Debug;
86
87	/// The starting slot of the epoch.
88	fn start_slot(&self) -> Self::Slot;
89	/// Produce the "end slot" of the epoch. This is NOT inclusive to the epoch,
90	/// i.e. the slots covered by the epoch are `self.start_slot() .. self.end_slot()`.
91	fn end_slot(&self) -> Self::Slot;
92	/// Increment the epoch data, using the next epoch descriptor.
93	fn increment(&self, descriptor: Self::NextEpochDescriptor) -> Self;
94}
95
96impl<'a, E: Epoch> From<&'a E> for EpochHeader<E> {
97	fn from(epoch: &'a E) -> EpochHeader<E> {
98		Self { start_slot: epoch.start_slot(), end_slot: epoch.end_slot() }
99	}
100}
101
102/// Header of epoch data, consisting of start and end slot.
103#[derive(Eq, PartialEq, Encode, Decode, Debug)]
104pub struct EpochHeader<E: Epoch> {
105	/// The starting slot of the epoch.
106	pub start_slot: E::Slot,
107	/// The end slot of the epoch. This is NOT inclusive to the epoch,
108	/// i.e. the slots covered by the epoch are `self.start_slot() .. self.end_slot()`.
109	pub end_slot: E::Slot,
110}
111
112impl<E: Epoch> Clone for EpochHeader<E> {
113	fn clone(&self) -> Self {
114		Self { start_slot: self.start_slot, end_slot: self.end_slot }
115	}
116}
117
118/// Position of the epoch identifier.
119#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
120pub enum EpochIdentifierPosition {
121	/// The identifier points to a genesis epoch `epoch_0`.
122	Genesis0,
123	/// The identifier points to a genesis epoch `epoch_1`.
124	Genesis1,
125	/// The identifier points to a regular epoch.
126	Regular,
127}
128
129/// Epoch identifier.
130#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
131pub struct EpochIdentifier<Hash, Number> {
132	/// Location of the epoch.
133	pub position: EpochIdentifierPosition,
134	/// Hash of the block when the epoch is signaled.
135	pub hash: Hash,
136	/// Number of the block when the epoch is signaled.
137	pub number: Number,
138}
139
140/// The viable epoch under which a block can be verified.
141///
142/// If this is the first non-genesis block in the chain, then it will
143/// hold an `UnimportedGenesis` epoch.
144pub enum ViableEpoch<E, ERef = E> {
145	/// Unimported genesis viable epoch data.
146	UnimportedGenesis(E),
147	/// Regular viable epoch data.
148	Signaled(ERef),
149}
150
151impl<E, ERef> AsRef<E> for ViableEpoch<E, ERef>
152where
153	ERef: Borrow<E>,
154{
155	fn as_ref(&self) -> &E {
156		match *self {
157			ViableEpoch::UnimportedGenesis(ref e) => e,
158			ViableEpoch::Signaled(ref e) => e.borrow(),
159		}
160	}
161}
162
163impl<E, ERef> AsMut<E> for ViableEpoch<E, ERef>
164where
165	ERef: BorrowMut<E>,
166{
167	fn as_mut(&mut self) -> &mut E {
168		match *self {
169			ViableEpoch::UnimportedGenesis(ref mut e) => e,
170			ViableEpoch::Signaled(ref mut e) => e.borrow_mut(),
171		}
172	}
173}
174
175impl<E, ERef> ViableEpoch<E, ERef>
176where
177	E: Epoch + Clone,
178	ERef: Borrow<E>,
179{
180	/// Extract the underlying epoch, disregarding the fact that a genesis
181	/// epoch may be unimported.
182	pub fn into_cloned_inner(self) -> E {
183		match self {
184			ViableEpoch::UnimportedGenesis(e) => e,
185			ViableEpoch::Signaled(e) => e.borrow().clone(),
186		}
187	}
188
189	/// Get cloned value for the viable epoch.
190	pub fn into_cloned(self) -> ViableEpoch<E, E> {
191		match self {
192			ViableEpoch::UnimportedGenesis(e) => ViableEpoch::UnimportedGenesis(e),
193			ViableEpoch::Signaled(e) => ViableEpoch::Signaled(e.borrow().clone()),
194		}
195	}
196
197	/// Increment the epoch, yielding an `IncrementedEpoch` to be imported
198	/// into the fork-tree.
199	pub fn increment(&self, next_descriptor: E::NextEpochDescriptor) -> IncrementedEpoch<E> {
200		let next = self.as_ref().increment(next_descriptor);
201		let to_persist = match *self {
202			ViableEpoch::UnimportedGenesis(ref epoch_0) => {
203				PersistedEpoch::Genesis(epoch_0.clone(), next)
204			},
205			ViableEpoch::Signaled(_) => PersistedEpoch::Regular(next),
206		};
207
208		IncrementedEpoch(to_persist)
209	}
210}
211
212/// Descriptor for a viable epoch.
213#[derive(PartialEq, Eq, Clone, Debug)]
214pub enum ViableEpochDescriptor<Hash, Number, E: Epoch> {
215	/// The epoch is an unimported genesis, with given start slot number.
216	UnimportedGenesis(E::Slot),
217	/// The epoch is signaled and has been imported, with given identifier and header.
218	Signaled(EpochIdentifier<Hash, Number>, EpochHeader<E>),
219}
220
221impl<Hash, Number, E: Epoch> ViableEpochDescriptor<Hash, Number, E> {
222	/// Start slot of the descriptor.
223	pub fn start_slot(&self) -> E::Slot {
224		match self {
225			Self::UnimportedGenesis(start_slot) => *start_slot,
226			Self::Signaled(_, header) => header.start_slot,
227		}
228	}
229}
230
231/// Persisted epoch stored in EpochChanges.
232#[derive(Clone, Encode, Decode, Debug)]
233pub enum PersistedEpoch<E> {
234	/// Genesis persisted epoch data. epoch_0, epoch_1.
235	Genesis(E, E),
236	/// Regular persisted epoch data. epoch_n.
237	Regular(E),
238}
239
240impl<E> PersistedEpoch<E> {
241	/// Returns if this is a genesis epoch.
242	pub fn is_genesis(&self) -> bool {
243		matches!(self, Self::Genesis(_, _))
244	}
245}
246
247impl<'a, E: Epoch> From<&'a PersistedEpoch<E>> for PersistedEpochHeader<E> {
248	fn from(epoch: &'a PersistedEpoch<E>) -> Self {
249		match epoch {
250			PersistedEpoch::Genesis(ref epoch_0, ref epoch_1) => {
251				PersistedEpochHeader::Genesis(epoch_0.into(), epoch_1.into())
252			},
253			PersistedEpoch::Regular(ref epoch_n) => PersistedEpochHeader::Regular(epoch_n.into()),
254		}
255	}
256}
257
258impl<E: Epoch> PersistedEpoch<E> {
259	/// Map the epoch to a different type using a conversion function.
260	pub fn map<B, F, Hash, Number>(self, h: &Hash, n: &Number, f: &mut F) -> PersistedEpoch<B>
261	where
262		B: Epoch<Slot = E::Slot>,
263		F: FnMut(&Hash, &Number, E) -> B,
264	{
265		match self {
266			PersistedEpoch::Genesis(epoch_0, epoch_1) => {
267				PersistedEpoch::Genesis(f(h, n, epoch_0), f(h, n, epoch_1))
268			},
269			PersistedEpoch::Regular(epoch_n) => PersistedEpoch::Regular(f(h, n, epoch_n)),
270		}
271	}
272}
273
274/// Persisted epoch header stored in ForkTree.
275#[derive(Encode, Decode, PartialEq, Eq, Debug)]
276pub enum PersistedEpochHeader<E: Epoch> {
277	/// Genesis persisted epoch header. epoch_0, epoch_1.
278	Genesis(EpochHeader<E>, EpochHeader<E>),
279	/// Regular persisted epoch header. epoch_n.
280	Regular(EpochHeader<E>),
281}
282
283impl<E: Epoch> Clone for PersistedEpochHeader<E> {
284	fn clone(&self) -> Self {
285		match self {
286			Self::Genesis(epoch_0, epoch_1) => Self::Genesis(epoch_0.clone(), epoch_1.clone()),
287			Self::Regular(epoch_n) => Self::Regular(epoch_n.clone()),
288		}
289	}
290}
291
292impl<E: Epoch> PersistedEpochHeader<E> {
293	/// Map the epoch header to a different type.
294	pub fn map<B>(self) -> PersistedEpochHeader<B>
295	where
296		B: Epoch<Slot = E::Slot>,
297	{
298		match self {
299			PersistedEpochHeader::Genesis(epoch_0, epoch_1) => PersistedEpochHeader::Genesis(
300				EpochHeader { start_slot: epoch_0.start_slot, end_slot: epoch_0.end_slot },
301				EpochHeader { start_slot: epoch_1.start_slot, end_slot: epoch_1.end_slot },
302			),
303			PersistedEpochHeader::Regular(epoch_n) => PersistedEpochHeader::Regular(EpochHeader {
304				start_slot: epoch_n.start_slot,
305				end_slot: epoch_n.end_slot,
306			}),
307		}
308	}
309}
310
311/// A fresh, incremented epoch to import into the underlying fork-tree.
312///
313/// Create this with `ViableEpoch::increment`.
314#[must_use = "Freshly-incremented epoch must be imported with `EpochChanges::import`"]
315pub struct IncrementedEpoch<E: Epoch>(PersistedEpoch<E>);
316
317impl<E: Epoch> AsRef<E> for IncrementedEpoch<E> {
318	fn as_ref(&self) -> &E {
319		match self.0 {
320			PersistedEpoch::Genesis(_, ref epoch_1) => epoch_1,
321			PersistedEpoch::Regular(ref epoch_n) => epoch_n,
322		}
323	}
324}
325
326/// Tree of all epoch changes across all *seen* forks. Data stored in tree is
327/// the hash and block number of the block signaling the epoch change, and the
328/// epoch that was signalled at that block.
329///
330/// The first epoch, epoch_0, is special cased by saying that it starts at
331/// slot number of the first block in the chain. When bootstrapping a chain,
332/// there can be multiple competing block #1s, so we have to ensure that the overlaid
333/// DAG doesn't get confused.
334///
335/// The first block of every epoch should be producing a descriptor for the next
336/// epoch - this is checked in higher-level code. So the first block of epoch_0 contains
337/// a descriptor for epoch_1. We special-case these and bundle them together in the
338/// same DAG entry, pinned to a specific block #1.
339///
340/// Further epochs (epoch_2, ..., epoch_n) each get their own entry.
341#[derive(Clone, Encode, Decode, Debug)]
342pub struct EpochChanges<Hash, Number, E: Epoch> {
343	inner: ForkTree<Hash, Number, PersistedEpochHeader<E>>,
344	epochs: BTreeMap<(Hash, Number), PersistedEpoch<E>>,
345}
346
347// create a fake header hash which hasn't been included in the chain.
348fn fake_head_hash<H: AsRef<[u8]> + AsMut<[u8]> + Clone>(parent_hash: &H) -> H {
349	let mut h = parent_hash.clone();
350	// dirty trick: flip the first bit of the parent hash to create a hash
351	// which has not been in the chain before (assuming a strong hash function).
352	h.as_mut()[0] ^= 0b10000000;
353	h
354}
355
356impl<Hash, Number, E: Epoch> Default for EpochChanges<Hash, Number, E>
357where
358	Hash: PartialEq + Ord,
359	Number: Ord,
360{
361	fn default() -> Self {
362		EpochChanges { inner: ForkTree::new(), epochs: BTreeMap::new() }
363	}
364}
365
366impl<Hash, Number, E: Epoch> EpochChanges<Hash, Number, E>
367where
368	Hash: PartialEq + Ord + AsRef<[u8]> + AsMut<[u8]> + Copy + std::fmt::Debug,
369	Number: Ord + One + Zero + Add<Output = Number> + Sub<Output = Number> + Copy + std::fmt::Debug,
370{
371	/// Create a new epoch change.
372	pub fn new() -> Self {
373		Self::default()
374	}
375
376	/// Rebalances the tree of epoch changes so that it is sorted by length of
377	/// fork (longest fork first).
378	pub fn rebalance(&mut self) {
379		self.inner.rebalance()
380	}
381
382	/// Map the epoch changes from one storing data to a different one.
383	pub fn map<B, F>(self, mut f: F) -> EpochChanges<Hash, Number, B>
384	where
385		B: Epoch<Slot = E::Slot>,
386		F: FnMut(&Hash, &Number, E) -> B,
387	{
388		EpochChanges {
389			inner: self.inner.map(&mut |_, _, header: PersistedEpochHeader<E>| header.map()),
390			epochs: self
391				.epochs
392				.into_iter()
393				.map(|((hash, number), epoch)| ((hash, number), epoch.map(&hash, &number, &mut f)))
394				.collect(),
395		}
396	}
397
398	/// Prune out finalized epochs, except for the ancestor of the finalized
399	/// block. The given slot should be the slot number at which the finalized
400	/// block was authored.
401	pub fn prune_finalized<D: IsDescendentOfBuilder<Hash>>(
402		&mut self,
403		descendent_of_builder: D,
404		hash: &Hash,
405		number: Number,
406		slot: E::Slot,
407	) -> Result<(), fork_tree::Error<D::Error>> {
408		let is_descendent_of = descendent_of_builder.build_is_descendent_of(None);
409
410		let predicate = |epoch: &PersistedEpochHeader<E>| match *epoch {
411			PersistedEpochHeader::Genesis(_, ref epoch_1) => epoch_1.start_slot <= slot,
412			PersistedEpochHeader::Regular(ref epoch_n) => epoch_n.start_slot <= slot,
413		};
414
415		// Prune any epochs which could not be _live_ as of the children of the
416		// finalized block, i.e. re-root the fork tree to the oldest ancestor of
417		// (hash, number) where `epoch.start_slot() <= finalized_slot`.
418		let removed = self.inner.prune(hash, &number, &is_descendent_of, &predicate)?;
419
420		for (hash, number, _) in removed {
421			self.epochs.remove(&(hash, number));
422		}
423
424		Ok(())
425	}
426
427	/// Get a reference to an epoch with given identifier.
428	pub fn epoch(&self, id: &EpochIdentifier<Hash, Number>) -> Option<&E> {
429		self.epochs.get(&(id.hash, id.number)).and_then(|v| match v {
430			PersistedEpoch::Genesis(ref epoch_0, _)
431				if id.position == EpochIdentifierPosition::Genesis0 =>
432			{
433				Some(epoch_0)
434			},
435			PersistedEpoch::Genesis(_, ref epoch_1)
436				if id.position == EpochIdentifierPosition::Genesis1 =>
437			{
438				Some(epoch_1)
439			},
440			PersistedEpoch::Regular(ref epoch_n)
441				if id.position == EpochIdentifierPosition::Regular =>
442			{
443				Some(epoch_n)
444			},
445			_ => None,
446		})
447	}
448
449	/// Get a reference to a viable epoch with given descriptor.
450	pub fn viable_epoch<G>(
451		&self,
452		descriptor: &ViableEpochDescriptor<Hash, Number, E>,
453		make_genesis: G,
454	) -> Option<ViableEpoch<E, &E>>
455	where
456		G: FnOnce(E::Slot) -> E,
457	{
458		match descriptor {
459			ViableEpochDescriptor::UnimportedGenesis(slot) => {
460				Some(ViableEpoch::UnimportedGenesis(make_genesis(*slot)))
461			},
462			ViableEpochDescriptor::Signaled(identifier, _) => {
463				self.epoch(identifier).map(ViableEpoch::Signaled)
464			},
465		}
466	}
467
468	/// Get a mutable reference to an epoch with given identifier.
469	pub fn epoch_mut(&mut self, id: &EpochIdentifier<Hash, Number>) -> Option<&mut E> {
470		self.epochs.get_mut(&(id.hash, id.number)).and_then(|v| match v {
471			PersistedEpoch::Genesis(ref mut epoch_0, _)
472				if id.position == EpochIdentifierPosition::Genesis0 =>
473			{
474				Some(epoch_0)
475			},
476			PersistedEpoch::Genesis(_, ref mut epoch_1)
477				if id.position == EpochIdentifierPosition::Genesis1 =>
478			{
479				Some(epoch_1)
480			},
481			PersistedEpoch::Regular(ref mut epoch_n)
482				if id.position == EpochIdentifierPosition::Regular =>
483			{
484				Some(epoch_n)
485			},
486			_ => None,
487		})
488	}
489
490	/// Get a mutable reference to a viable epoch with given descriptor.
491	pub fn viable_epoch_mut<G>(
492		&mut self,
493		descriptor: &ViableEpochDescriptor<Hash, Number, E>,
494		make_genesis: G,
495	) -> Option<ViableEpoch<E, &mut E>>
496	where
497		G: FnOnce(E::Slot) -> E,
498	{
499		match descriptor {
500			ViableEpochDescriptor::UnimportedGenesis(slot) => {
501				Some(ViableEpoch::UnimportedGenesis(make_genesis(*slot)))
502			},
503			ViableEpochDescriptor::Signaled(identifier, _) => {
504				self.epoch_mut(identifier).map(ViableEpoch::Signaled)
505			},
506		}
507	}
508
509	/// Get the epoch data from an epoch descriptor.
510	///
511	/// Note that this function ignores the fact that an genesis epoch might need to be imported.
512	/// Mostly useful for testing.
513	pub fn epoch_data<G>(
514		&self,
515		descriptor: &ViableEpochDescriptor<Hash, Number, E>,
516		make_genesis: G,
517	) -> Option<E>
518	where
519		G: FnOnce(E::Slot) -> E,
520		E: Clone,
521	{
522		match descriptor {
523			ViableEpochDescriptor::UnimportedGenesis(slot) => Some(make_genesis(*slot)),
524			ViableEpochDescriptor::Signaled(identifier, _) => self.epoch(identifier).cloned(),
525		}
526	}
527
528	/// Finds the epoch data for a child of the given block. Similar to
529	/// `epoch_descriptor_for_child_of` but returns the full data.
530	///
531	/// Note that this function ignores the fact that an genesis epoch might need to be imported.
532	/// Mostly useful for testing.
533	pub fn epoch_data_for_child_of<D: IsDescendentOfBuilder<Hash>, G>(
534		&self,
535		descendent_of_builder: D,
536		parent_hash: &Hash,
537		parent_number: Number,
538		slot: E::Slot,
539		make_genesis: G,
540	) -> Result<Option<E>, fork_tree::Error<D::Error>>
541	where
542		G: FnOnce(E::Slot) -> E,
543		E: Clone,
544	{
545		let descriptor = self.epoch_descriptor_for_child_of(
546			descendent_of_builder,
547			parent_hash,
548			parent_number,
549			slot,
550		)?;
551
552		Ok(descriptor.and_then(|des| self.epoch_data(&des, make_genesis)))
553	}
554
555	/// Finds the epoch for a child of the given block, assuming the given slot number.
556	///
557	/// If the returned epoch is an `UnimportedGenesis` epoch, it should be imported into the
558	/// tree.
559	pub fn epoch_descriptor_for_child_of<D: IsDescendentOfBuilder<Hash>>(
560		&self,
561		descendent_of_builder: D,
562		parent_hash: &Hash,
563		parent_number: Number,
564		slot: E::Slot,
565	) -> Result<Option<ViableEpochDescriptor<Hash, Number, E>>, fork_tree::Error<D::Error>> {
566		if parent_number == Zero::zero() {
567			// need to insert the genesis epoch.
568			return Ok(Some(ViableEpochDescriptor::UnimportedGenesis(slot)));
569		}
570
571		// find_node_where will give you the node in the fork-tree which is an ancestor
572		// of the `parent_hash` by default. if the last epoch was signalled at the parent_hash,
573		// then it won't be returned. we need to create a new fake chain head hash which
574		// "descends" from our parent-hash.
575		let fake_head_hash = fake_head_hash(parent_hash);
576
577		let is_descendent_of =
578			descendent_of_builder.build_is_descendent_of(Some((fake_head_hash, *parent_hash)));
579
580		// We want to find the deepest node in the tree which is an ancestor
581		// of our block and where the start slot of the epoch was before the
582		// slot of our block. The genesis special-case doesn't need to look
583		// at epoch_1 -- all we're doing here is figuring out which node
584		// we need.
585		let predicate = |epoch: &PersistedEpochHeader<E>| match *epoch {
586			PersistedEpochHeader::Genesis(ref epoch_0, _) => epoch_0.start_slot <= slot,
587			PersistedEpochHeader::Regular(ref epoch_n) => epoch_n.start_slot <= slot,
588		};
589
590		self.inner
591			.find_node_where(
592				&fake_head_hash,
593				&(parent_number + One::one()),
594				&is_descendent_of,
595				&predicate,
596			)
597			.map(|n| {
598				n.map(|node| {
599					(
600						match node.data {
601							// Ok, we found our node.
602							// and here we figure out which of the internal epochs
603							// of a genesis node to use based on their start slot.
604							PersistedEpochHeader::Genesis(ref epoch_0, ref epoch_1) => {
605								if epoch_1.start_slot <= slot {
606									(EpochIdentifierPosition::Genesis1, epoch_1.clone())
607								} else {
608									(EpochIdentifierPosition::Genesis0, epoch_0.clone())
609								}
610							},
611							PersistedEpochHeader::Regular(ref epoch_n) => {
612								(EpochIdentifierPosition::Regular, epoch_n.clone())
613							},
614						},
615						node,
616					)
617				})
618				.map(|((position, header), node)| {
619					ViableEpochDescriptor::Signaled(
620						EpochIdentifier { position, hash: node.hash, number: node.number },
621						header,
622					)
623				})
624			})
625	}
626
627	/// Import a new epoch-change, signalled at the given block.
628	///
629	/// This assumes that the given block is prospective (i.e. has not been
630	/// imported yet), but its parent has. This is why the parent hash needs
631	/// to be provided.
632	pub fn import<D: IsDescendentOfBuilder<Hash>>(
633		&mut self,
634		descendent_of_builder: D,
635		hash: Hash,
636		number: Number,
637		parent_hash: Hash,
638		epoch: IncrementedEpoch<E>,
639	) -> Result<(), fork_tree::Error<D::Error>> {
640		let is_descendent_of =
641			descendent_of_builder.build_is_descendent_of(Some((hash, parent_hash)));
642		let IncrementedEpoch(epoch) = epoch;
643		let header = PersistedEpochHeader::<E>::from(&epoch);
644
645		let res = self.inner.import(hash, number, header, &is_descendent_of);
646
647		match res {
648			Ok(_) | Err(fork_tree::Error::Duplicate) => {
649				self.epochs.insert((hash, number), epoch);
650				Ok(())
651			},
652			Err(e) => Err(e),
653		}
654	}
655
656	/// Reset to a specified pair of epochs, as if they were announced at blocks `parent_hash` and
657	/// `hash`.
658	pub fn reset(&mut self, parent_hash: Hash, hash: Hash, number: Number, current: E, next: E) {
659		self.inner = ForkTree::new();
660		self.epochs.clear();
661		let persisted = PersistedEpoch::Regular(current);
662		let header = PersistedEpochHeader::from(&persisted);
663		let _res = self.inner.import(parent_hash, number - One::one(), header, &|_, _| {
664			Ok(false) as Result<bool, fork_tree::Error<ClientError>>
665		});
666		self.epochs.insert((parent_hash, number - One::one()), persisted);
667
668		let persisted = PersistedEpoch::Regular(next);
669		let header = PersistedEpochHeader::from(&persisted);
670		let _res = self.inner.import(hash, number, header, &|_, _| {
671			Ok(true) as Result<bool, fork_tree::Error<ClientError>>
672		});
673		self.epochs.insert((hash, number), persisted);
674	}
675
676	/// Revert to a specified block given its `hash` and `number`.
677	/// This removes all the epoch changes information that were announced by
678	/// all the given block descendants.
679	pub fn revert<D: IsDescendentOfBuilder<Hash>>(
680		&mut self,
681		descendent_of_builder: D,
682		hash: Hash,
683		number: Number,
684	) {
685		let is_descendent_of = descendent_of_builder.build_is_descendent_of(None);
686
687		let filter = |node_hash: &Hash, node_num: &Number, _: &PersistedEpochHeader<E>| {
688			if number >= *node_num &&
689				(is_descendent_of(node_hash, &hash).unwrap_or_default() || *node_hash == hash)
690			{
691				// Continue the search in this subtree.
692				FilterAction::KeepNode
693			} else if number < *node_num && is_descendent_of(&hash, node_hash).unwrap_or_default() {
694				// Found a node to be removed.
695				FilterAction::Remove
696			} else {
697				// Not a parent or child of the one we're looking for, stop processing this branch.
698				FilterAction::KeepTree
699			}
700		};
701
702		self.inner.drain_filter(filter).for_each(|(h, n, _)| {
703			self.epochs.remove(&(h, n));
704		});
705	}
706
707	/// Return the inner fork tree (mostly useful for testing)
708	pub fn tree(&self) -> &ForkTree<Hash, Number, PersistedEpochHeader<E>> {
709		&self.inner
710	}
711}
712
713/// Type alias to produce the epoch-changes tree from a block type.
714pub type EpochChangesFor<Block, Epoch> =
715	EpochChanges<<Block as BlockT>::Hash, NumberFor<Block>, Epoch>;
716
717/// A shared epoch changes tree.
718pub type SharedEpochChanges<Block, Epoch> =
719	sc_consensus::shared_data::SharedData<EpochChangesFor<Block, Epoch>>;
720
721#[cfg(test)]
722mod tests {
723	use super::{Epoch as EpochT, *};
724
725	#[derive(Debug, PartialEq)]
726	pub struct TestError;
727
728	impl std::fmt::Display for TestError {
729		fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
730			write!(f, "TestError")
731		}
732	}
733
734	impl std::error::Error for TestError {}
735
736	impl<'a, F: 'a, H: 'a + PartialEq + std::fmt::Debug> IsDescendentOfBuilder<H> for &'a F
737	where
738		F: Fn(&H, &H) -> Result<bool, TestError>,
739	{
740		type Error = TestError;
741		type IsDescendentOf = Box<dyn Fn(&H, &H) -> Result<bool, TestError> + 'a>;
742
743		fn build_is_descendent_of(&self, current: Option<(H, H)>) -> Self::IsDescendentOf {
744			let f = *self;
745			Box::new(move |base, head| {
746				let mut head = head;
747
748				if let Some((ref c_head, ref c_parent)) = current {
749					if head == c_head {
750						if base == c_parent {
751							return Ok(true);
752						} else {
753							head = c_parent;
754						}
755					}
756				}
757
758				f(base, head)
759			})
760		}
761	}
762
763	type Hash = [u8; 1];
764	type Slot = u64;
765
766	#[derive(Debug, Clone, Eq, PartialEq)]
767	struct Epoch {
768		start_slot: Slot,
769		duration: Slot,
770	}
771
772	impl EpochT for Epoch {
773		type NextEpochDescriptor = ();
774		type Slot = Slot;
775
776		fn increment(&self, _: ()) -> Self {
777			Epoch { start_slot: self.start_slot + self.duration, duration: self.duration }
778		}
779
780		fn end_slot(&self) -> Slot {
781			self.start_slot + self.duration
782		}
783
784		fn start_slot(&self) -> Slot {
785			self.start_slot
786		}
787	}
788
789	#[test]
790	fn genesis_epoch_is_created_but_not_imported() {
791		// A - B
792		//  \
793		//   — C
794		//
795		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
796			match (base, *block) {
797				(b"A", b) => Ok(b == *b"B" || b == *b"C" || b == *b"D"),
798				(b"B", b) | (b"C", b) => Ok(b == *b"D"),
799				(b"0", _) => Ok(true),
800				_ => Ok(false),
801			}
802		};
803
804		let epoch_changes = EpochChanges::<_, _, Epoch>::new();
805		let genesis_epoch = epoch_changes
806			.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 10101)
807			.unwrap()
808			.unwrap();
809
810		match genesis_epoch {
811			ViableEpochDescriptor::UnimportedGenesis(slot) => {
812				assert_eq!(slot, 10101u64);
813			},
814			_ => panic!("should be unimported genesis"),
815		};
816
817		let genesis_epoch_2 = epoch_changes
818			.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 10102)
819			.unwrap()
820			.unwrap();
821
822		match genesis_epoch_2 {
823			ViableEpochDescriptor::UnimportedGenesis(slot) => {
824				assert_eq!(slot, 10102u64);
825			},
826			_ => panic!("should be unimported genesis"),
827		};
828	}
829
830	#[test]
831	fn epoch_changes_between_blocks() {
832		// A - B
833		//  \
834		//   — C
835		//
836		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
837			match (base, *block) {
838				(b"A", b) => Ok(b == *b"B" || b == *b"C" || b == *b"D"),
839				(b"B", b) | (b"C", b) => Ok(b == *b"D"),
840				(b"0", _) => Ok(true),
841				_ => Ok(false),
842			}
843		};
844
845		let make_genesis = |slot| Epoch { start_slot: slot, duration: 100 };
846
847		let mut epoch_changes = EpochChanges::<_, _, Epoch>::new();
848		let genesis_epoch = epoch_changes
849			.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 100)
850			.unwrap()
851			.unwrap();
852
853		assert_eq!(genesis_epoch, ViableEpochDescriptor::UnimportedGenesis(100));
854
855		let import_epoch_1 =
856			epoch_changes.viable_epoch(&genesis_epoch, &make_genesis).unwrap().increment(());
857		let epoch_1 = import_epoch_1.as_ref().clone();
858
859		epoch_changes
860			.import(&is_descendent_of, *b"A", 1, *b"0", import_epoch_1)
861			.unwrap();
862		let genesis_epoch = epoch_changes.epoch_data(&genesis_epoch, &make_genesis).unwrap();
863
864		assert!(is_descendent_of(b"0", b"A").unwrap());
865
866		let end_slot = genesis_epoch.end_slot();
867		assert_eq!(end_slot, epoch_1.start_slot);
868
869		{
870			// x is still within the genesis epoch.
871			let x = epoch_changes
872				.epoch_data_for_child_of(&is_descendent_of, b"A", 1, end_slot - 1, &make_genesis)
873				.unwrap()
874				.unwrap();
875
876			assert_eq!(x, genesis_epoch);
877		}
878
879		{
880			// x is now at the next epoch, because the block is now at the
881			// start slot of epoch 1.
882			let x = epoch_changes
883				.epoch_data_for_child_of(&is_descendent_of, b"A", 1, end_slot, &make_genesis)
884				.unwrap()
885				.unwrap();
886
887			assert_eq!(x, epoch_1);
888		}
889
890		{
891			// x is now at the next epoch, because the block is now after
892			// start slot of epoch 1.
893			let x = epoch_changes
894				.epoch_data_for_child_of(
895					&is_descendent_of,
896					b"A",
897					1,
898					epoch_1.end_slot() - 1,
899					&make_genesis,
900				)
901				.unwrap()
902				.unwrap();
903
904			assert_eq!(x, epoch_1);
905		}
906	}
907
908	#[test]
909	fn two_block_ones_dont_conflict() {
910		//     X - Y
911		//   /
912		// 0 - A - B
913		//
914		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
915			match (base, *block) {
916				(b"A", b) => Ok(b == *b"B"),
917				(b"X", b) => Ok(b == *b"Y"),
918				(b"0", _) => Ok(true),
919				_ => Ok(false),
920			}
921		};
922
923		let duration = 100;
924
925		let make_genesis = |slot| Epoch { start_slot: slot, duration };
926
927		let mut epoch_changes = EpochChanges::new();
928		let next_descriptor = ();
929
930		// insert genesis epoch for A
931		{
932			let genesis_epoch_a_descriptor = epoch_changes
933				.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 100)
934				.unwrap()
935				.unwrap();
936
937			let incremented_epoch = epoch_changes
938				.viable_epoch(&genesis_epoch_a_descriptor, &make_genesis)
939				.unwrap()
940				.increment(next_descriptor);
941
942			epoch_changes
943				.import(&is_descendent_of, *b"A", 1, *b"0", incremented_epoch)
944				.unwrap();
945		}
946
947		// insert genesis epoch for X
948		{
949			let genesis_epoch_x_descriptor = epoch_changes
950				.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 1000)
951				.unwrap()
952				.unwrap();
953
954			let incremented_epoch = epoch_changes
955				.viable_epoch(&genesis_epoch_x_descriptor, &make_genesis)
956				.unwrap()
957				.increment(next_descriptor);
958
959			epoch_changes
960				.import(&is_descendent_of, *b"X", 1, *b"0", incremented_epoch)
961				.unwrap();
962		}
963
964		// now check that the genesis epochs for our respective block 1s
965		// respect the chain structure.
966		{
967			let epoch_for_a_child = epoch_changes
968				.epoch_data_for_child_of(&is_descendent_of, b"A", 1, 101, &make_genesis)
969				.unwrap()
970				.unwrap();
971
972			assert_eq!(epoch_for_a_child, make_genesis(100));
973
974			let epoch_for_x_child = epoch_changes
975				.epoch_data_for_child_of(&is_descendent_of, b"X", 1, 1001, &make_genesis)
976				.unwrap()
977				.unwrap();
978
979			assert_eq!(epoch_for_x_child, make_genesis(1000));
980
981			let epoch_for_x_child_before_genesis = epoch_changes
982				.epoch_data_for_child_of(&is_descendent_of, b"X", 1, 101, &make_genesis)
983				.unwrap();
984
985			// even though there is a genesis epoch at that slot, it's not in
986			// this chain.
987			assert!(epoch_for_x_child_before_genesis.is_none());
988		}
989	}
990
991	#[test]
992	fn prune_removes_stale_nodes() {
993		//     +---D       +-------F
994		//     |           |
995		// 0---A---B--(x)--C--(y)--G
996		// |       |
997		// +---H   +-------E
998		//
999		//  Test parameters:
1000		//  - epoch duration: 100
1001		//
1002		//  We are going to prune the tree at:
1003		//  - 'x', a node between B and C
1004		//  - 'y', a node between C and G
1005
1006		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
1007			match (base, block) {
1008				(b"0", _) => Ok(true),
1009				(b"A", b) => Ok(b != b"0"),
1010				(b"B", b) => Ok(b != b"0" && b != b"A" && b != b"D"),
1011				(b"C", b) => Ok(b == b"F" || b == b"G" || b == b"y"),
1012				(b"x", b) => Ok(b == b"C" || b == b"F" || b == b"G" || b == b"y"),
1013				(b"y", b) => Ok(b == b"G"),
1014				_ => Ok(false),
1015			}
1016		};
1017
1018		let mut epoch_changes = EpochChanges::new();
1019
1020		let mut import_at = |slot, hash: &Hash, number, parent_hash, parent_number| {
1021			let make_genesis = |slot| Epoch { start_slot: slot, duration: 100 };
1022			// Get epoch descriptor valid for 'slot'
1023			let epoch_descriptor = epoch_changes
1024				.epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot)
1025				.unwrap()
1026				.unwrap();
1027			// Increment it
1028			let next_epoch_desc = epoch_changes
1029				.viable_epoch(&epoch_descriptor, &make_genesis)
1030				.unwrap()
1031				.increment(());
1032			// Assign it to hash/number
1033			epoch_changes
1034				.import(&is_descendent_of, *hash, number, *parent_hash, next_epoch_desc)
1035				.unwrap();
1036		};
1037
1038		import_at(100, b"A", 10, b"0", 0);
1039		import_at(200, b"B", 20, b"A", 10);
1040		import_at(300, b"C", 30, b"B", 20);
1041		import_at(200, b"D", 20, b"A", 10);
1042		import_at(300, b"E", 30, b"B", 20);
1043		import_at(400, b"F", 40, b"C", 30);
1044		import_at(400, b"G", 40, b"C", 30);
1045		import_at(100, b"H", 10, b"0", 0);
1046
1047		let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect();
1048		nodes.sort();
1049		assert_eq!(nodes, vec![b"A", b"B", b"C", b"D", b"E", b"F", b"G", b"H"]);
1050
1051		// Finalize block 'x' @ number 25, slot 230
1052		// This should prune all nodes imported by blocks with a number < 25 that are not
1053		// ancestors of 'x' and all nodes before the one holding the epoch information
1054		// to which 'x' belongs to (i.e. before A).
1055
1056		epoch_changes.prune_finalized(&is_descendent_of, b"x", 25, 230).unwrap();
1057
1058		let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect();
1059		nodes.sort();
1060		assert_eq!(nodes, vec![b"A", b"B", b"C", b"F", b"G"]);
1061
1062		// Finalize block y @ number 35, slot 330
1063		// This should prune all nodes imported by blocks with a number < 35 that are not
1064		// ancestors of 'y' and all nodes before the one holding the epoch information
1065		// to which 'y' belongs to (i.e. before B).
1066
1067		epoch_changes.prune_finalized(&is_descendent_of, b"y", 35, 330).unwrap();
1068
1069		let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect();
1070		nodes.sort();
1071		assert_eq!(nodes, vec![b"B", b"C", b"G"]);
1072	}
1073
1074	#[test]
1075	fn near_genesis_prune_works() {
1076		// [X]: announces next epoch change (i.e. adds a node in the epoch changes tree)
1077		//
1078		// 0--[A]--B--C--D--E--[G]--H--I--J--K--[L]
1079		//                  +
1080		//                  \--[F]
1081
1082		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
1083			match (block, base) {
1084				(b"A", b"0") |
1085				(b"B", b"0" | b"A") |
1086				(b"C", b"0" | b"A" | b"B") |
1087				(b"D", b"0" | b"A" | b"B" | b"C") |
1088				(b"E", b"0" | b"A" | b"B" | b"C" | b"D") |
1089				(b"F", b"0" | b"A" | b"B" | b"C" | b"D" | b"E") |
1090				(b"G", b"0" | b"A" | b"B" | b"C" | b"D" | b"E") |
1091				(b"H", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G") |
1092				(b"I", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H") |
1093				(b"J", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I") |
1094				(b"K", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I" | b"J") |
1095				(
1096					b"L",
1097					b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I" | b"J" | b"K",
1098				) => Ok(true),
1099				_ => Ok(false),
1100			}
1101		};
1102
1103		let mut epoch_changes = EpochChanges::new();
1104
1105		let epoch = Epoch { start_slot: 278183811, duration: 5 };
1106		let epoch = PersistedEpoch::Genesis(epoch.clone(), epoch.increment(()));
1107
1108		epoch_changes
1109			.import(&is_descendent_of, *b"A", 1, Default::default(), IncrementedEpoch(epoch))
1110			.unwrap();
1111
1112		let import_at = |epoch_changes: &mut EpochChanges<_, _, Epoch>,
1113		                 slot,
1114		                 hash: &Hash,
1115		                 number,
1116		                 parent_hash,
1117		                 parent_number| {
1118			let make_genesis = |slot| Epoch { start_slot: slot, duration: 5 };
1119			// Get epoch descriptor valid for 'slot'
1120			let epoch_descriptor = epoch_changes
1121				.epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot)
1122				.unwrap()
1123				.unwrap();
1124			// Increment it
1125			let next_epoch_desc = epoch_changes
1126				.viable_epoch(&epoch_descriptor, &make_genesis)
1127				.unwrap()
1128				.increment(());
1129			// Assign it to hash/number
1130			epoch_changes
1131				.import(&is_descendent_of, *hash, number, *parent_hash, next_epoch_desc)
1132				.unwrap();
1133		};
1134
1135		// Should not prune anything
1136		epoch_changes.prune_finalized(&is_descendent_of, b"C", 3, 278183813).unwrap();
1137
1138		import_at(&mut epoch_changes, 278183816, b"G", 6, b"E", 5);
1139		import_at(&mut epoch_changes, 278183816, b"F", 6, b"E", 5);
1140
1141		// Should not prune anything since we are on epoch0
1142		epoch_changes.prune_finalized(&is_descendent_of, b"C", 3, 278183813).unwrap();
1143		let mut list: Vec<_> = epoch_changes.inner.iter().map(|e| e.0).collect();
1144		list.sort();
1145		assert_eq!(list, vec![b"A", b"F", b"G"]);
1146
1147		import_at(&mut epoch_changes, 278183821, b"L", 11, b"K", 10);
1148
1149		// Should prune any fork of our ancestor not in the canonical chain (i.e. "F")
1150		epoch_changes.prune_finalized(&is_descendent_of, b"J", 9, 278183819).unwrap();
1151		let mut list: Vec<_> = epoch_changes.inner.iter().map(|e| e.0).collect();
1152		list.sort();
1153		assert_eq!(list, vec![b"A", b"G", b"L"]);
1154	}
1155}