1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use crate::{blockcfg::HeaderHash, blockchain::Ref};
use std::sync::Arc;

/// list of pre-computed checkpoints from a given [`Ref`].
///
/// [`Ref`]: ./struct.Ref.html
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Checkpoints(Vec<HeaderHash>);

impl Checkpoints {
    /// create a new list of checkpoints from the given starting point (tip).
    ///
    /// The function make use of the `Ref` object pointing to previous epoch in order
    /// to populate _interestingly_ spaced checkpoints.
    ///
    /// For now the algorithm provide the current block, the parent, the last block of the
    /// previous epoch, the last block of the epoch before that... until the block0.
    pub fn new_from(from: Arc<Ref>) -> Self {
        let mut checkpoints = vec![from.hash(), from.block_parent_hash()];

        let block0_hash = from.ledger().get_static_parameters().block0_initial_hash;

        let mut ignore_prev = 0;
        let mut current_ref = from;
        while let Some(prev_epoch) = current_ref.last_ref_previous_epoch() {
            current_ref = Arc::clone(prev_epoch);

            for _ in 0..ignore_prev {
                if let Some(prev_epoch) = current_ref.last_ref_previous_epoch() {
                    current_ref = Arc::clone(prev_epoch);
                } else {
                    break;
                }
            }

            let hash = current_ref.hash();

            // prevent the `from`'s parent to appear twice in the event the parent is also
            // the last block of the previous epoch.
            if checkpoints[checkpoints.len() - 1] != hash {
                ignore_prev += 1;
                checkpoints.push(hash);
            }
        }

        if block0_hash != checkpoints[1] {
            checkpoints.push(block0_hash);
        }

        Checkpoints(checkpoints)
    }

    pub fn iter(&self) -> impl Iterator<Item = &HeaderHash> {
        self.0.iter()
    }

    pub fn as_slice(&self) -> &[HeaderHash] {
        self.0.as_slice()
    }
}

impl AsRef<[HeaderHash]> for Checkpoints {
    fn as_ref(&self) -> &[HeaderHash] {
        self.as_slice()
    }
}

impl IntoIterator for Checkpoints {
    type Item = HeaderHash;
    type IntoIter = ::std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl From<Checkpoints> for Vec<HeaderHash> {
    fn from(checkpoints: Checkpoints) -> Self {
        checkpoints.0
    }
}