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 },
205 ViableEpoch::Signaled(_) => PersistedEpoch::Regular(next),
206 };
207
208 IncrementedEpoch(to_persist)
209 }
210}
211
212#[derive(PartialEq, Eq, Clone, Debug)]
214pub enum ViableEpochDescriptor<Hash, Number, E: Epoch> {
215 UnimportedGenesis(E::Slot),
217 Signaled(EpochIdentifier<Hash, Number>, EpochHeader<E>),
219}
220
221impl<Hash, Number, E: Epoch> ViableEpochDescriptor<Hash, Number, E> {
222 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#[derive(Clone, Encode, Decode, Debug)]
233pub enum PersistedEpoch<E> {
234 Genesis(E, E),
236 Regular(E),
238}
239
240impl<E> PersistedEpoch<E> {
241 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 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#[derive(Encode, Decode, PartialEq, Eq, Debug)]
276pub enum PersistedEpochHeader<E: Epoch> {
277 Genesis(EpochHeader<E>, EpochHeader<E>),
279 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 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#[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#[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
347fn fake_head_hash<H: AsRef<[u8]> + AsMut<[u8]> + Clone>(parent_hash: &H) -> H {
349 let mut h = parent_hash.clone();
350 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 pub fn new() -> Self {
373 Self::default()
374 }
375
376 pub fn rebalance(&mut self) {
379 self.inner.rebalance()
380 }
381
382 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 pub fn prune_finalized<D: IsDescendentOfBuilder<Hash>>(
402 &mut self,
403 descendent_of_builder: D,
404 hash: &Hash,
405 number: Number,
406 slot: E::Slot,
407 ) -> Result<(), fork_tree::Error<D::Error>> {
408 let is_descendent_of = descendent_of_builder.build_is_descendent_of(None);
409
410 let predicate = |epoch: &PersistedEpochHeader<E>| match *epoch {
411 PersistedEpochHeader::Genesis(_, ref epoch_1) => epoch_1.start_slot <= slot,
412 PersistedEpochHeader::Regular(ref epoch_n) => epoch_n.start_slot <= slot,
413 };
414
415 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 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 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 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 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 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 pub fn epoch_data_for_child_of<D: IsDescendentOfBuilder<Hash>, G>(
534 &self,
535 descendent_of_builder: D,
536 parent_hash: &Hash,
537 parent_number: Number,
538 slot: E::Slot,
539 make_genesis: G,
540 ) -> Result<Option<E>, fork_tree::Error<D::Error>>
541 where
542 G: FnOnce(E::Slot) -> E,
543 E: Clone,
544 {
545 let descriptor = self.epoch_descriptor_for_child_of(
546 descendent_of_builder,
547 parent_hash,
548 parent_number,
549 slot,
550 )?;
551
552 Ok(descriptor.and_then(|des| self.epoch_data(&des, make_genesis)))
553 }
554
555 pub fn epoch_descriptor_for_child_of<D: IsDescendentOfBuilder<Hash>>(
560 &self,
561 descendent_of_builder: D,
562 parent_hash: &Hash,
563 parent_number: Number,
564 slot: E::Slot,
565 ) -> Result<Option<ViableEpochDescriptor<Hash, Number, E>>, fork_tree::Error<D::Error>> {
566 if parent_number == Zero::zero() {
567 return Ok(Some(ViableEpochDescriptor::UnimportedGenesis(slot)));
569 }
570
571 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 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 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 pub fn import<D: IsDescendentOfBuilder<Hash>>(
633 &mut self,
634 descendent_of_builder: D,
635 hash: Hash,
636 number: Number,
637 parent_hash: Hash,
638 epoch: IncrementedEpoch<E>,
639 ) -> Result<(), fork_tree::Error<D::Error>> {
640 let is_descendent_of =
641 descendent_of_builder.build_is_descendent_of(Some((hash, parent_hash)));
642 let IncrementedEpoch(epoch) = epoch;
643 let header = PersistedEpochHeader::<E>::from(&epoch);
644
645 let res = self.inner.import(hash, number, header, &is_descendent_of);
646
647 match res {
648 Ok(_) | Err(fork_tree::Error::Duplicate) => {
649 self.epochs.insert((hash, number), epoch);
650 Ok(())
651 },
652 Err(e) => Err(e),
653 }
654 }
655
656 pub fn reset(&mut self, parent_hash: Hash, hash: Hash, number: Number, current: E, next: E) {
659 self.inner = ForkTree::new();
660 self.epochs.clear();
661 let persisted = PersistedEpoch::Regular(current);
662 let header = PersistedEpochHeader::from(&persisted);
663 let _res = self.inner.import(parent_hash, number - One::one(), header, &|_, _| {
664 Ok(false) as Result<bool, fork_tree::Error<ClientError>>
665 });
666 self.epochs.insert((parent_hash, number - One::one()), persisted);
667
668 let persisted = PersistedEpoch::Regular(next);
669 let header = PersistedEpochHeader::from(&persisted);
670 let _res = self.inner.import(hash, number, header, &|_, _| {
671 Ok(true) as Result<bool, fork_tree::Error<ClientError>>
672 });
673 self.epochs.insert((hash, number), persisted);
674 }
675
676 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 FilterAction::KeepNode
693 } else if number < *node_num && is_descendent_of(&hash, node_hash).unwrap_or_default() {
694 FilterAction::Remove
696 } else {
697 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 pub fn tree(&self) -> &ForkTree<Hash, Number, PersistedEpochHeader<E>> {
709 &self.inner
710 }
711}
712
713pub type EpochChangesFor<Block, Epoch> =
715 EpochChanges<<Block as BlockT>::Hash, NumberFor<Block>, Epoch>;
716
717pub type SharedEpochChanges<Block, Epoch> =
719 sc_consensus::shared_data::SharedData<EpochChangesFor<Block, Epoch>>;
720
721#[cfg(test)]
722mod tests {
723 use super::{Epoch as EpochT, *};
724
725 #[derive(Debug, PartialEq)]
726 pub struct TestError;
727
728 impl std::fmt::Display for TestError {
729 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
730 write!(f, "TestError")
731 }
732 }
733
734 impl std::error::Error for TestError {}
735
736 impl<'a, F: 'a, H: 'a + PartialEq + std::fmt::Debug> IsDescendentOfBuilder<H> for &'a F
737 where
738 F: Fn(&H, &H) -> Result<bool, TestError>,
739 {
740 type Error = TestError;
741 type IsDescendentOf = Box<dyn Fn(&H, &H) -> Result<bool, TestError> + 'a>;
742
743 fn build_is_descendent_of(&self, current: Option<(H, H)>) -> Self::IsDescendentOf {
744 let f = *self;
745 Box::new(move |base, head| {
746 let mut head = head;
747
748 if let Some((ref c_head, ref c_parent)) = current {
749 if head == c_head {
750 if base == c_parent {
751 return Ok(true);
752 } else {
753 head = c_parent;
754 }
755 }
756 }
757
758 f(base, head)
759 })
760 }
761 }
762
763 type Hash = [u8; 1];
764 type Slot = u64;
765
766 #[derive(Debug, Clone, Eq, PartialEq)]
767 struct Epoch {
768 start_slot: Slot,
769 duration: Slot,
770 }
771
772 impl EpochT for Epoch {
773 type NextEpochDescriptor = ();
774 type Slot = Slot;
775
776 fn increment(&self, _: ()) -> Self {
777 Epoch { start_slot: self.start_slot + self.duration, duration: self.duration }
778 }
779
780 fn end_slot(&self) -> Slot {
781 self.start_slot + self.duration
782 }
783
784 fn start_slot(&self) -> Slot {
785 self.start_slot
786 }
787 }
788
789 #[test]
790 fn genesis_epoch_is_created_but_not_imported() {
791 let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
796 match (base, *block) {
797 (b"A", b) => Ok(b == *b"B" || b == *b"C" || b == *b"D"),
798 (b"B", b) | (b"C", b) => Ok(b == *b"D"),
799 (b"0", _) => Ok(true),
800 _ => Ok(false),
801 }
802 };
803
804 let epoch_changes = EpochChanges::<_, _, Epoch>::new();
805 let genesis_epoch = epoch_changes
806 .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 10101)
807 .unwrap()
808 .unwrap();
809
810 match genesis_epoch {
811 ViableEpochDescriptor::UnimportedGenesis(slot) => {
812 assert_eq!(slot, 10101u64);
813 },
814 _ => panic!("should be unimported genesis"),
815 };
816
817 let genesis_epoch_2 = epoch_changes
818 .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 10102)
819 .unwrap()
820 .unwrap();
821
822 match genesis_epoch_2 {
823 ViableEpochDescriptor::UnimportedGenesis(slot) => {
824 assert_eq!(slot, 10102u64);
825 },
826 _ => panic!("should be unimported genesis"),
827 };
828 }
829
830 #[test]
831 fn epoch_changes_between_blocks() {
832 let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
837 match (base, *block) {
838 (b"A", b) => Ok(b == *b"B" || b == *b"C" || b == *b"D"),
839 (b"B", b) | (b"C", b) => Ok(b == *b"D"),
840 (b"0", _) => Ok(true),
841 _ => Ok(false),
842 }
843 };
844
845 let make_genesis = |slot| Epoch { start_slot: slot, duration: 100 };
846
847 let mut epoch_changes = EpochChanges::<_, _, Epoch>::new();
848 let genesis_epoch = epoch_changes
849 .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 100)
850 .unwrap()
851 .unwrap();
852
853 assert_eq!(genesis_epoch, ViableEpochDescriptor::UnimportedGenesis(100));
854
855 let import_epoch_1 =
856 epoch_changes.viable_epoch(&genesis_epoch, &make_genesis).unwrap().increment(());
857 let epoch_1 = import_epoch_1.as_ref().clone();
858
859 epoch_changes
860 .import(&is_descendent_of, *b"A", 1, *b"0", import_epoch_1)
861 .unwrap();
862 let genesis_epoch = epoch_changes.epoch_data(&genesis_epoch, &make_genesis).unwrap();
863
864 assert!(is_descendent_of(b"0", b"A").unwrap());
865
866 let end_slot = genesis_epoch.end_slot();
867 assert_eq!(end_slot, epoch_1.start_slot);
868
869 {
870 let x = epoch_changes
872 .epoch_data_for_child_of(&is_descendent_of, b"A", 1, end_slot - 1, &make_genesis)
873 .unwrap()
874 .unwrap();
875
876 assert_eq!(x, genesis_epoch);
877 }
878
879 {
880 let x = epoch_changes
883 .epoch_data_for_child_of(&is_descendent_of, b"A", 1, end_slot, &make_genesis)
884 .unwrap()
885 .unwrap();
886
887 assert_eq!(x, epoch_1);
888 }
889
890 {
891 let x = epoch_changes
894 .epoch_data_for_child_of(
895 &is_descendent_of,
896 b"A",
897 1,
898 epoch_1.end_slot() - 1,
899 &make_genesis,
900 )
901 .unwrap()
902 .unwrap();
903
904 assert_eq!(x, epoch_1);
905 }
906 }
907
908 #[test]
909 fn two_block_ones_dont_conflict() {
910 let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
915 match (base, *block) {
916 (b"A", b) => Ok(b == *b"B"),
917 (b"X", b) => Ok(b == *b"Y"),
918 (b"0", _) => Ok(true),
919 _ => Ok(false),
920 }
921 };
922
923 let duration = 100;
924
925 let make_genesis = |slot| Epoch { start_slot: slot, duration };
926
927 let mut epoch_changes = EpochChanges::new();
928 let next_descriptor = ();
929
930 {
932 let genesis_epoch_a_descriptor = epoch_changes
933 .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 100)
934 .unwrap()
935 .unwrap();
936
937 let incremented_epoch = epoch_changes
938 .viable_epoch(&genesis_epoch_a_descriptor, &make_genesis)
939 .unwrap()
940 .increment(next_descriptor);
941
942 epoch_changes
943 .import(&is_descendent_of, *b"A", 1, *b"0", incremented_epoch)
944 .unwrap();
945 }
946
947 {
949 let genesis_epoch_x_descriptor = epoch_changes
950 .epoch_descriptor_for_child_of(&is_descendent_of, b"0", 0, 1000)
951 .unwrap()
952 .unwrap();
953
954 let incremented_epoch = epoch_changes
955 .viable_epoch(&genesis_epoch_x_descriptor, &make_genesis)
956 .unwrap()
957 .increment(next_descriptor);
958
959 epoch_changes
960 .import(&is_descendent_of, *b"X", 1, *b"0", incremented_epoch)
961 .unwrap();
962 }
963
964 {
967 let epoch_for_a_child = epoch_changes
968 .epoch_data_for_child_of(&is_descendent_of, b"A", 1, 101, &make_genesis)
969 .unwrap()
970 .unwrap();
971
972 assert_eq!(epoch_for_a_child, make_genesis(100));
973
974 let epoch_for_x_child = epoch_changes
975 .epoch_data_for_child_of(&is_descendent_of, b"X", 1, 1001, &make_genesis)
976 .unwrap()
977 .unwrap();
978
979 assert_eq!(epoch_for_x_child, make_genesis(1000));
980
981 let epoch_for_x_child_before_genesis = epoch_changes
982 .epoch_data_for_child_of(&is_descendent_of, b"X", 1, 101, &make_genesis)
983 .unwrap();
984
985 assert!(epoch_for_x_child_before_genesis.is_none());
988 }
989 }
990
991 #[test]
992 fn prune_removes_stale_nodes() {
993 let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
1007 match (base, block) {
1008 (b"0", _) => Ok(true),
1009 (b"A", b) => Ok(b != b"0"),
1010 (b"B", b) => Ok(b != b"0" && b != b"A" && b != b"D"),
1011 (b"C", b) => Ok(b == b"F" || b == b"G" || b == b"y"),
1012 (b"x", b) => Ok(b == b"C" || b == b"F" || b == b"G" || b == b"y"),
1013 (b"y", b) => Ok(b == b"G"),
1014 _ => Ok(false),
1015 }
1016 };
1017
1018 let mut epoch_changes = EpochChanges::new();
1019
1020 let mut import_at = |slot, hash: &Hash, number, parent_hash, parent_number| {
1021 let make_genesis = |slot| Epoch { start_slot: slot, duration: 100 };
1022 let epoch_descriptor = epoch_changes
1024 .epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot)
1025 .unwrap()
1026 .unwrap();
1027 let next_epoch_desc = epoch_changes
1029 .viable_epoch(&epoch_descriptor, &make_genesis)
1030 .unwrap()
1031 .increment(());
1032 epoch_changes
1034 .import(&is_descendent_of, *hash, number, *parent_hash, next_epoch_desc)
1035 .unwrap();
1036 };
1037
1038 import_at(100, b"A", 10, b"0", 0);
1039 import_at(200, b"B", 20, b"A", 10);
1040 import_at(300, b"C", 30, b"B", 20);
1041 import_at(200, b"D", 20, b"A", 10);
1042 import_at(300, b"E", 30, b"B", 20);
1043 import_at(400, b"F", 40, b"C", 30);
1044 import_at(400, b"G", 40, b"C", 30);
1045 import_at(100, b"H", 10, b"0", 0);
1046
1047 let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect();
1048 nodes.sort();
1049 assert_eq!(nodes, vec![b"A", b"B", b"C", b"D", b"E", b"F", b"G", b"H"]);
1050
1051 epoch_changes.prune_finalized(&is_descendent_of, b"x", 25, 230).unwrap();
1057
1058 let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect();
1059 nodes.sort();
1060 assert_eq!(nodes, vec![b"A", b"B", b"C", b"F", b"G"]);
1061
1062 epoch_changes.prune_finalized(&is_descendent_of, b"y", 35, 330).unwrap();
1068
1069 let mut nodes: Vec<_> = epoch_changes.tree().iter().map(|(h, _, _)| h).collect();
1070 nodes.sort();
1071 assert_eq!(nodes, vec![b"B", b"C", b"G"]);
1072 }
1073
1074 #[test]
1075 fn near_genesis_prune_works() {
1076 let is_descendent_of = |base: &Hash, block: &Hash| -> Result<bool, TestError> {
1083 match (block, base) {
1084 (b"A", b"0") |
1085 (b"B", b"0" | b"A") |
1086 (b"C", b"0" | b"A" | b"B") |
1087 (b"D", b"0" | b"A" | b"B" | b"C") |
1088 (b"E", b"0" | b"A" | b"B" | b"C" | b"D") |
1089 (b"F", b"0" | b"A" | b"B" | b"C" | b"D" | b"E") |
1090 (b"G", b"0" | b"A" | b"B" | b"C" | b"D" | b"E") |
1091 (b"H", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G") |
1092 (b"I", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H") |
1093 (b"J", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I") |
1094 (b"K", b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I" | b"J") |
1095 (
1096 b"L",
1097 b"0" | b"A" | b"B" | b"C" | b"D" | b"E" | b"G" | b"H" | b"I" | b"J" | b"K",
1098 ) => Ok(true),
1099 _ => Ok(false),
1100 }
1101 };
1102
1103 let mut epoch_changes = EpochChanges::new();
1104
1105 let epoch = Epoch { start_slot: 278183811, duration: 5 };
1106 let epoch = PersistedEpoch::Genesis(epoch.clone(), epoch.increment(()));
1107
1108 epoch_changes
1109 .import(&is_descendent_of, *b"A", 1, Default::default(), IncrementedEpoch(epoch))
1110 .unwrap();
1111
1112 let import_at = |epoch_changes: &mut EpochChanges<_, _, Epoch>,
1113 slot,
1114 hash: &Hash,
1115 number,
1116 parent_hash,
1117 parent_number| {
1118 let make_genesis = |slot| Epoch { start_slot: slot, duration: 5 };
1119 let epoch_descriptor = epoch_changes
1121 .epoch_descriptor_for_child_of(&is_descendent_of, parent_hash, parent_number, slot)
1122 .unwrap()
1123 .unwrap();
1124 let next_epoch_desc = epoch_changes
1126 .viable_epoch(&epoch_descriptor, &make_genesis)
1127 .unwrap()
1128 .increment(());
1129 epoch_changes
1131 .import(&is_descendent_of, *hash, number, *parent_hash, next_epoch_desc)
1132 .unwrap();
1133 };
1134
1135 epoch_changes.prune_finalized(&is_descendent_of, b"C", 3, 278183813).unwrap();
1137
1138 import_at(&mut epoch_changes, 278183816, b"G", 6, b"E", 5);
1139 import_at(&mut epoch_changes, 278183816, b"F", 6, b"E", 5);
1140
1141 epoch_changes.prune_finalized(&is_descendent_of, b"C", 3, 278183813).unwrap();
1143 let mut list: Vec<_> = epoch_changes.inner.iter().map(|e| e.0).collect();
1144 list.sort();
1145 assert_eq!(list, vec![b"A", b"F", b"G"]);
1146
1147 import_at(&mut epoch_changes, 278183821, b"L", 11, b"K", 10);
1148
1149 epoch_changes.prune_finalized(&is_descendent_of, b"J", 9, 278183819).unwrap();
1151 let mut list: Vec<_> = epoch_changes.inner.iter().map(|e| e.0).collect();
1152 list.sort();
1153 assert_eq!(list, vec![b"A", b"G", b"L"]);
1154 }
1155}