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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::fmt::{Debug, Display, Error as FmtError, Formatter};

use parity_scale_codec::{Decode, Encode};

use crate::{
    phron_primitives::Header,
    justification::PhronJustification,
    sync::{
        substrate::{
            chain_status::{Error as ChainStatusError, SubstrateChainStatus},
            BlockId,
        },
        BlockStatus, ChainStatus, Justification as JustificationT, UnverifiedJustification,
    },
};

/// Proper `PhronJustification` or a variant indicating virtual justification
/// for the genesis block, which is the only block that can be the top finalized
/// block with no proper justification.
#[derive(Clone, Debug, Encode, Decode)]
pub enum InnerJustification {
    PhronJustification(PhronJustification),
    Genesis,
}

/// A justification, including the related header.
#[derive(Clone, Debug, Encode, Decode)]
pub struct Justification {
    pub header: Header,
    pub inner_justification: InnerJustification,
}

impl Justification {
    pub fn phron_justification(header: Header, phron_justification: PhronJustification) -> Self {
        Justification {
            header,
            inner_justification: InnerJustification::PhronJustification(phron_justification),
        }
    }

    pub fn genesis_justification(header: Header) -> Self {
        Justification {
            header,
            inner_justification: InnerJustification::Genesis,
        }
    }

    pub fn into_inner(self) -> InnerJustification {
        self.inner_justification
    }
}

impl UnverifiedJustification for Justification {
    type UnverifiedHeader = Header;

    fn header(&self) -> &Self::UnverifiedHeader {
        &self.header
    }
}

impl JustificationT for Justification {
    type Header = Header;
    type Unverified = Self;

    fn header(&self) -> &Self::Header {
        &self.header
    }

    fn into_unverified(self) -> Self::Unverified {
        self
    }
}

#[derive(Debug)]
pub enum TranslateError {
    ChainStatus(ChainStatusError),
    NoBlock,
}

impl Display for TranslateError {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        use TranslateError::*;
        match self {
            ChainStatus(e) => {
                write!(f, "error retrieving block status: {e}")
            }
            NoBlock => write!(f, "block not present"),
        }
    }
}

impl From<ChainStatusError> for TranslateError {
    fn from(value: ChainStatusError) -> Self {
        TranslateError::ChainStatus(value)
    }
}

/// Translates raw phron justifications into ones acceptable to sync.
#[derive(Clone)]
pub struct JustificationTranslator {
    chain_status: SubstrateChainStatus,
}

impl JustificationTranslator {
    pub fn new(chain_status: SubstrateChainStatus) -> Self {
        Self { chain_status }
    }

    pub fn translate(
        &self,
        phron_justification: PhronJustification,
        block_id: BlockId,
    ) -> Result<Justification, TranslateError> {
        use BlockStatus::*;
        match self.chain_status.status_of(block_id)? {
            Justified(Justification { header, .. }) | Present(header) => Ok(
                Justification::phron_justification(header, phron_justification),
            ),
            Unknown => Err(TranslateError::NoBlock),
        }
    }
}