Skip to main content

hotshot_types/new_protocol/
proposal.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    data::{
5        EpochNumber, Leaf2, QuorumProposal2, QuorumProposalWrapper, ViewChangeEvidence2, ViewNumber,
6    },
7    drb::DrbResult,
8    simple_certificate::{
9        LightClientStateUpdateCertificateV2, QuorumCertificate2, SimpleCertificate,
10        SuccessThreshold, TimeoutEvidence, UpgradeCertificate2, optional_timeout_evidence,
11    },
12    simple_vote::{HasEpoch, Vote2Data},
13    traits::node_implementation::NodeType,
14    vote::HasViewNumber,
15};
16
17/// Proposal to append a block.
18#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
19#[serde(bound(deserialize = ""))]
20pub struct Proposal<T: NodeType> {
21    /// The block header to append
22    pub block_header: T::BlockHeader,
23
24    /// view number for the proposal
25    pub view_number: ViewNumber,
26
27    /// The epoch number corresponding to the block number.
28    pub epoch: EpochNumber,
29
30    /// certificate that the proposal is chaining from
31    pub justify_qc: QuorumCertificate2<T>,
32
33    /// certificate proving the last block of the epoch is decided
34    pub next_epoch_justify_qc: Option<SimpleCertificate<T, Vote2Data<T>, SuccessThreshold>>,
35
36    /// Possible upgrade certificate, which the leader may optionally attach.
37    /// It binds this proposal's epoch; the `Leaf2` carries it stripped of it.
38    pub upgrade_certificate: Option<UpgradeCertificate2<T>>,
39
40    /// Possible timeout certificate.
41    ///
42    /// If the `justify_qc` is not for a proposal in the immediately preceding
43    /// view, then a timeout certificate must be attached.
44    #[serde(with = "optional_timeout_evidence")]
45    pub view_change_evidence: Option<TimeoutEvidence<T>>,
46
47    /// The DRB result for the next epoch.
48    ///
49    /// This is required only for the last block of the epoch. Nodes will verify
50    /// that it's consistent with the result from their computations.
51    #[serde(with = "serde_bytes")]
52    pub next_drb_result: Option<DrbResult>,
53
54    /// The light client state update certificate for the next epoch.
55    /// This is required for the epoch root.
56    pub state_cert: Option<LightClientStateUpdateCertificateV2<T>>,
57}
58
59impl<T: NodeType> HasViewNumber for Proposal<T> {
60    fn view_number(&self) -> ViewNumber {
61        self.view_number
62    }
63}
64
65impl<T: NodeType> HasEpoch for Proposal<T> {
66    fn epoch(&self) -> Option<EpochNumber> {
67        Some(self.epoch)
68    }
69}
70
71impl<T: NodeType> From<QuorumProposalWrapper<T>> for Proposal<T> {
72    fn from(wrapper: QuorumProposalWrapper<T>) -> Self {
73        let qp = wrapper.proposal;
74        let epoch = qp.epoch.unwrap_or(EpochNumber::new(0));
75        Self {
76            block_header: qp.block_header,
77            view_number: qp.view_number,
78            epoch,
79            justify_qc: qp.justify_qc,
80            next_epoch_justify_qc: None,
81            upgrade_certificate: qp
82                .upgrade_certificate
83                .map(|cert| UpgradeCertificate2::restore_epoch(cert, epoch)),
84            view_change_evidence: qp
85                .view_change_evidence
86                .and_then(ViewChangeEvidence2::timeout_evidence),
87            next_drb_result: qp.next_drb_result,
88            state_cert: qp.state_cert,
89        }
90    }
91}
92
93impl<T: NodeType> From<Proposal<T>> for QuorumProposalWrapper<T> {
94    fn from(p: Proposal<T>) -> Self {
95        QuorumProposalWrapper::from(QuorumProposal2 {
96            block_header: p.block_header,
97            view_number: p.view_number,
98            epoch: Some(p.epoch),
99            justify_qc: p.justify_qc,
100            next_epoch_justify_qc: None,
101            upgrade_certificate: p.upgrade_certificate.map(UpgradeCertificate2::strip_epoch),
102            view_change_evidence: p.view_change_evidence.map(ViewChangeEvidence2::from),
103            next_drb_result: p.next_drb_result,
104            state_cert: p.state_cert,
105        })
106    }
107}
108
109impl<T: NodeType> From<Proposal<T>> for Leaf2<T> {
110    fn from(p: Proposal<T>) -> Self {
111        QuorumProposalWrapper::from(p).into()
112    }
113}