referrerpolicy=no-referrer-when-downgrade

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