pezsc_consensus_epochs/
lib.rs

1// This file is part of Bizinikiwi.
2
3// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
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 pez_fork_tree::{FilterAction, ForkTree};
25use pezsc_client_api::utils::is_descendent_of;
26use pezsp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata};
27use pezsp_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 pez-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 pez-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<(), pez_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>, pez_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>>, pez_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 pez-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<(), pez_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(pez_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, pez_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, pez_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	pezsc_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		//
792		// A - B
793		//  \
794		//   — C
795		//
796		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
797			match (base, *block) {
798				(b"A", b) => Ok(b == *b"B" || b == *b"C" || b == *b"D"),
799				(b"B", b) | (b"C", b) => Ok(b == *b"D"),
800				(b"0", _) => Ok(true),
801				_ => Ok(false),
802			}
803		};
804
805		let epoch_changes = EpochChanges::<_, _, Epoch>::new();
806		let genesis_epoch = epoch_changes
807			.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 10101)
808			.unwrap()
809			.unwrap();
810
811		match genesis_epoch {
812			ViableEpochDescriptor::UnimportedGenesis(slot) => {
813				assert_eq!(slot, 10101u64);
814			},
815			_ => panic!("should be unimported genesis"),
816		};
817
818		let genesis_epoch_2 = epoch_changes
819			.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 10102)
820			.unwrap()
821			.unwrap();
822
823		match genesis_epoch_2 {
824			ViableEpochDescriptor::UnimportedGenesis(slot) => {
825				assert_eq!(slot, 10102u64);
826			},
827			_ => panic!("should be unimported genesis"),
828		};
829	}
830
831	#[test]
832	fn epoch_changes_between_blocks() {
833		//
834		// A - B
835		//  \
836		//   — C
837		//
838		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
839			match (base, *block) {
840				(b"A", b) => Ok(b == *b"B" || b == *b"C" || b == *b"D"),
841				(b"B", b) | (b"C", b) => Ok(b == *b"D"),
842				(b"0", _) => Ok(true),
843				_ => Ok(false),
844			}
845		};
846
847		let make_genesis = |slot| Epoch { start_slot: slot, duration: 100 };
848
849		let mut epoch_changes = EpochChanges::<_, _, Epoch>::new();
850		let genesis_epoch = epoch_changes
851			.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 100)
852			.unwrap()
853			.unwrap();
854
855		assert_eq!(genesis_epoch, ViableEpochDescriptor::UnimportedGenesis(100));
856
857		let import_epoch_1 =
858			epoch_changes.viable_epoch(&genesis_epoch, &make_genesis).unwrap().increment(());
859		let epoch_1 = import_epoch_1.as_ref().clone();
860
861		epoch_changes
862			.import(&is_descendent_of, *b"A", 1, *b"0", import_epoch_1)
863			.unwrap();
864		let genesis_epoch = epoch_changes.epoch_data(&genesis_epoch, &make_genesis).unwrap();
865
866		assert!(is_descendent_of(b"0", b"A").unwrap());
867
868		let end_slot = genesis_epoch.end_slot();
869		assert_eq!(end_slot, epoch_1.start_slot);
870
871		{
872			// x is still within the genesis epoch.
873			let x = epoch_changes
874				.epoch_data_for_child_of(&is_descendent_of, b"A", 1, end_slot - 1, &make_genesis)
875				.unwrap()
876				.unwrap();
877
878			assert_eq!(x, genesis_epoch);
879		}
880
881		{
882			// x is now at the next epoch, because the block is now at the
883			// start slot of epoch 1.
884			let x = epoch_changes
885				.epoch_data_for_child_of(&is_descendent_of, b"A", 1, end_slot, &make_genesis)
886				.unwrap()
887				.unwrap();
888
889			assert_eq!(x, epoch_1);
890		}
891
892		{
893			// x is now at the next epoch, because the block is now after
894			// start slot of epoch 1.
895			let x = epoch_changes
896				.epoch_data_for_child_of(
897					&is_descendent_of,
898					b"A",
899					1,
900					epoch_1.end_slot() - 1,
901					&make_genesis,
902				)
903				.unwrap()
904				.unwrap();
905
906			assert_eq!(x, epoch_1);
907		}
908	}
909
910	#[test]
911	fn two_block_ones_dont_conflict() {
912		//     X - Y
913		//   /
914		// 0 - A - B
915		//
916		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
917			match (base, *block) {
918				(b"A", b) => Ok(b == *b"B"),
919				(b"X", b) => Ok(b == *b"Y"),
920				(b"0", _) => Ok(true),
921				_ => Ok(false),
922			}
923		};
924
925		let duration = 100;
926
927		let make_genesis = |slot| Epoch { start_slot: slot, duration };
928
929		let mut epoch_changes = EpochChanges::new();
930		let next_descriptor = ();
931
932		// insert genesis epoch for A
933		{
934			let genesis_epoch_a_descriptor = epoch_changes
935				.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 100)
936				.unwrap()
937				.unwrap();
938
939			let incremented_epoch = epoch_changes
940				.viable_epoch(&genesis_epoch_a_descriptor, &make_genesis)
941				.unwrap()
942				.increment(next_descriptor);
943
944			epoch_changes
945				.import(&is_descendent_of, *b"A", 1, *b"0", incremented_epoch)
946				.unwrap();
947		}
948
949		// insert genesis epoch for X
950		{
951			let genesis_epoch_x_descriptor = epoch_changes
952				.epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 1000)
953				.unwrap()
954				.unwrap();
955
956			let incremented_epoch = epoch_changes
957				.viable_epoch(&genesis_epoch_x_descriptor, &make_genesis)
958				.unwrap()
959				.increment(next_descriptor);
960
961			epoch_changes
962				.import(&is_descendent_of, *b"X", 1, *b"0", incremented_epoch)
963				.unwrap();
964		}
965
966		// now check that the genesis epochs for our respective block 1s
967		// respect the chain structure.
968		{
969			let epoch_for_a_child = epoch_changes
970				.epoch_data_for_child_of(&is_descendent_of, b"A", 1, 101, &make_genesis)
971				.unwrap()
972				.unwrap();
973
974			assert_eq!(epoch_for_a_child, make_genesis(100));
975
976			let epoch_for_x_child = epoch_changes
977				.epoch_data_for_child_of(&is_descendent_of, b"X", 1, 1001, &make_genesis)
978				.unwrap()
979				.unwrap();
980
981			assert_eq!(epoch_for_x_child, make_genesis(1000));
982
983			let epoch_for_x_child_before_genesis = epoch_changes
984				.epoch_data_for_child_of(&is_descendent_of, b"X", 1, 101, &make_genesis)
985				.unwrap();
986
987			// even though there is a genesis epoch at that slot, it's not in
988			// this chain.
989			assert!(epoch_for_x_child_before_genesis.is_none());
990		}
991	}
992
993	#[test]
994	fn prune_removes_stale_nodes() {
995		//     +---D       +-------F
996		//     |           |
997		// 0---A---B--(x)--C--(y)--G
998		// |       |
999		// +---H   +-------E
1000		//
1001		//  Test parameters:
1002		//  - epoch duration: 100
1003		//
1004		//  We are going to prune the tree at:
1005		//  - 'x', a node between B and C
1006		//  - 'y', a node between C and G
1007
1008		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
1009			match (base, block) {
1010				(b"0", _) => Ok(true),
1011				(b"A", b) => Ok(b != b"0"),
1012				(b"B", b) => Ok(b != b"0" && b != b"A" && b != b"D"),
1013				(b"C", b) => Ok(b == b"F" || b == b"G" || b == b"y"),
1014				(b"x", b) => Ok(b == b"C" || b == b"F" || b == b"G" || b == b"y"),
1015				(b"y", b) => Ok(b == b"G"),
1016				_ => Ok(false),
1017			}
1018		};
1019
1020		let mut epoch_changes = EpochChanges::new();
1021
1022		let mut import_at = |slot, hash: &Hash, number, parent_hash, parent_number| {
1023			let make_genesis = |slot| Epoch { start_slot: slot, duration: 100 };
1024			// Get epoch descriptor valid for 'slot'
1025			let epoch_descriptor = epoch_changes
1026				.epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot)
1027				.unwrap()
1028				.unwrap();
1029			// Increment it
1030			let next_epoch_desc = epoch_changes
1031				.viable_epoch(&epoch_descriptor, &make_genesis)
1032				.unwrap()
1033				.increment(());
1034			// Assign it to hash/number
1035			epoch_changes
1036				.import(&is_descendent_of, *hash, number, *parent_hash, next_epoch_desc)
1037				.unwrap();
1038		};
1039
1040		import_at(100, b"A", 10, b"0", 0);
1041		import_at(200, b"B", 20, b"A", 10);
1042		import_at(300, b"C", 30, b"B", 20);
1043		import_at(200, b"D", 20, b"A", 10);
1044		import_at(300, b"E", 30, b"B", 20);
1045		import_at(400, b"F", 40, b"C", 30);
1046		import_at(400, b"G", 40, b"C", 30);
1047		import_at(100, b"H", 10, b"0", 0);
1048
1049		let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect();
1050		nodes.sort();
1051		assert_eq!(nodes, vec![b"A", b"B", b"C", b"D", b"E", b"F", b"G", b"H"]);
1052
1053		// Finalize block 'x' @ number 25, slot 230
1054		// This should prune all nodes imported by blocks with a number < 25 that are not
1055		// ancestors of 'x' and all nodes before the one holding the epoch information
1056		// to which 'x' belongs to (i.e. before A).
1057
1058		epoch_changes.prune_finalized(&is_descendent_of, b"x", 25, 230).unwrap();
1059
1060		let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect();
1061		nodes.sort();
1062		assert_eq!(nodes, vec![b"A", b"B", b"C", b"F", b"G"]);
1063
1064		// Finalize block y @ number 35, slot 330
1065		// This should prune all nodes imported by blocks with a number < 35 that are not
1066		// ancestors of 'y' and all nodes before the one holding the epoch information
1067		// to which 'y' belongs to (i.e. before B).
1068
1069		epoch_changes.prune_finalized(&is_descendent_of, b"y", 35, 330).unwrap();
1070
1071		let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect();
1072		nodes.sort();
1073		assert_eq!(nodes, vec![b"B", b"C", b"G"]);
1074	}
1075
1076	#[test]
1077	fn near_genesis_prune_works() {
1078		// [X]: announces next epoch change (i.e. adds a node in the epoch changes tree)
1079		//
1080		// 0--[A]--B--C--D--E--[G]--H--I--J--K--[L]
1081		//                  +
1082		//                  \--[F]
1083
1084		let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
1085			match (block, base) {
1086				| (b"A", b"0")
1087				| (b"B", b"0" | b"A")
1088				| (b"C", b"0" | b"A" | b"B")
1089				| (b"D", b"0" | b"A" | b"B" | b"C")
1090				| (b"E", b"0" | b"A" | b"B" | b"C" | b"D")
1091				| (b"F", b"0" | b"A" | b"B" | b"C" | b"D" | b"E")
1092				| (b"G", b"0" | b"A" | b"B" | b"C" | b"D" | b"E")
1093				| (b"H", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G")
1094				| (b"I", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H")
1095				| (b"J", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I")
1096				| (b"K", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I" | b"J")
1097				| (
1098					b"L",
1099					b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I" | b"J" | b"K",
1100				) => Ok(true),
1101				_ => Ok(false),
1102			}
1103		};
1104
1105		let mut epoch_changes = EpochChanges::new();
1106
1107		let epoch = Epoch { start_slot: 278183811, duration: 5 };
1108		let epoch = PersistedEpoch::Genesis(epoch.clone(), epoch.increment(()));
1109
1110		epoch_changes
1111			.import(&is_descendent_of, *b"A", 1, Default::default(), IncrementedEpoch(epoch))
1112			.unwrap();
1113
1114		let import_at = |epoch_changes: &mut EpochChanges<_, _, Epoch>,
1115		                 slot,
1116		                 hash: &Hash,
1117		                 number,
1118		                 parent_hash,
1119		                 parent_number| {
1120			let make_genesis = |slot| Epoch { start_slot: slot, duration: 5 };
1121			// Get epoch descriptor valid for 'slot'
1122			let epoch_descriptor = epoch_changes
1123				.epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot)
1124				.unwrap()
1125				.unwrap();
1126			// Increment it
1127			let next_epoch_desc = epoch_changes
1128				.viable_epoch(&epoch_descriptor, &make_genesis)
1129				.unwrap()
1130				.increment(());
1131			// Assign it to hash/number
1132			epoch_changes
1133				.import(&is_descendent_of, *hash, number, *parent_hash, next_epoch_desc)
1134				.unwrap();
1135		};
1136
1137		// Should not prune anything
1138		epoch_changes.prune_finalized(&is_descendent_of, b"C", 3, 278183813).unwrap();
1139
1140		import_at(&mut epoch_changes, 278183816, b"G", 6, b"E", 5);
1141		import_at(&mut epoch_changes, 278183816, b"F", 6, b"E", 5);
1142
1143		// Should not prune anything since we are on epoch0
1144		epoch_changes.prune_finalized(&is_descendent_of, b"C", 3, 278183813).unwrap();
1145		let mut list: Vec<_> = epoch_changes.inner.iter().map(|e| e.0).collect();
1146		list.sort();
1147		assert_eq!(list, vec![b"A", b"F", b"G"]);
1148
1149		import_at(&mut epoch_changes, 278183821, b"L", 11, b"K", 10);
1150
1151		// Should prune any fork of our ancestor not in the canonical chain (i.e. "F")
1152		epoch_changes.prune_finalized(&is_descendent_of, b"J", 9, 278183819).unwrap();
1153		let mut list: Vec<_> = epoch_changes.inner.iter().map(|e| e.0).collect();
1154		list.sort();
1155		assert_eq!(list, vec![b"A", b"G", b"L"]);
1156	}
1157}