1pub 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
34pub trait IsDescendentOfBuilder<Hash> {
36 type Error: std::error::Error;
38 type IsDescendentOf: Fn(&Hash, &Hash) -> Result<bool, Self::Error>;
41
42 fn build_is_descendent_of(&self, current: Option<(Hash, Hash)>) -> Self::IsDescendentOf;
49}
50
51pub fn descendent_query<H, Block>(client: &H) -> HeaderBackendDescendentBuilder<&H, Block> {
53 HeaderBackendDescendentBuilder(client, std::marker::PhantomData)
54}
55
56pub 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
77pub trait Epoch: std::fmt::Debug {
82 type NextEpochDescriptor;
84 type Slot: Ord + Copy + std::fmt::Debug;
86
87 fn start_slot(&self) -> Self::Slot;
89 fn end_slot(&self) -> Self::Slot;
92 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#[derive(Eq, PartialEq, Encode, Decode, Debug)]
104pub struct EpochHeader<E: Epoch> {
105 pub start_slot: E::Slot,
107 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#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
120pub enum EpochIdentifierPosition {
121 Genesis0,
123 Genesis1,
125 Regular,
127}
128
129#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
131pub struct EpochIdentifier<Hash, Number> {
132 pub position: EpochIdentifierPosition,
134 pub hash: Hash,
136 pub number: Number,
138}
139
140pub enum ViableEpoch<E, ERef = E> {
145 UnimportedGenesis(E),
147 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 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 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 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#[derive(PartialEq, Eq, Clone, Debug)]
213pub enum ViableEpochDescriptor<Hash, Number, E: Epoch> {
214 UnimportedGenesis(E::Slot),
216 Signaled(EpochIdentifier<Hash, Number>, EpochHeader<E>),
218}
219
220impl<Hash, Number, E: Epoch> ViableEpochDescriptor<Hash, Number, E> {
221 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#[derive(Clone, Encode, Decode, Debug)]
232pub enum PersistedEpoch<E> {
233 Genesis(E, E),
235 Regular(E),
237}
238
239impl<E> PersistedEpoch<E> {
240 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 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#[derive(Encode, Decode, PartialEq, Eq, Debug)]
273pub enum PersistedEpochHeader<E: Epoch> {
274 Genesis(EpochHeader<E>, EpochHeader<E>),
276 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 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#[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#[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
344fn fake_head_hash<H: AsRef<[u8]> + AsMut<[u8]> + Clone>(parent_hash: &H) -> H {
346 let mut h = parent_hash.clone();
347 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 pub fn new() -> Self {
370 Self::default()
371 }
372
373 pub fn rebalance(&mut self) {
376 self.inner.rebalance()
377 }
378
379 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 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 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 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 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 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 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 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 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 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 return Ok(Some(ViableEpochDescriptor::UnimportedGenesis(slot)))
550 }
551
552 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 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 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 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 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 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 FilterAction::KeepNode
673 } else if number < *node_num && is_descendent_of(&hash, node_hash).unwrap_or_default() {
674 FilterAction::Remove
676 } else {
677 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 pub fn tree(&self) -> &ForkTree<Hash, Number, PersistedEpochHeader<E>> {
689 &self.inner
690 }
691}
692
693pub type EpochChangesFor<Block, Epoch> =
695 EpochChanges<<Block as BlockT>::Hash, NumberFor<Block>, Epoch>;
696
697pub 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 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 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 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 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 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 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 {
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 {
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 {
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 assert!(epoch_for_x_child_before_genesis.is_none());
970 }
971 }
972
973 #[test]
974 fn prune_removes_stale_nodes() {
975 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 let epoch_descriptor = epoch_changes
1006 .epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot)
1007 .unwrap()
1008 .unwrap();
1009 let next_epoch_desc = epoch_changes
1011 .viable_epoch(&epoch_descriptor, &make_genesis)
1012 .unwrap()
1013 .increment(());
1014 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 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 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 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 let epoch_descriptor = epoch_changes
1103 .epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot)
1104 .unwrap()
1105 .unwrap();
1106 let next_epoch_desc = epoch_changes
1108 .viable_epoch(&epoch_descriptor, &make_genesis)
1109 .unwrap()
1110 .increment(());
1111 epoch_changes
1113 .import(&is_descendent_of, *hash, number, *parent_hash, next_epoch_desc)
1114 .unwrap();
1115 };
1116
1117 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 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 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}