1use crate::{
9 common::{Author, Payload, Round},
10 quorum_cert::{QuorumCert, QuorumCertUnchecked},
11 vote_data::VoteData,
12};
13use diem_crypto::hash::HashValue;
14use diem_crypto_derive::{BCSCryptoHash, CryptoHasher};
15use diem_types::{
16 block_info::BlockInfo,
17 ledger_info::{LedgerInfo, LedgerInfoWithSignatures},
18 transaction::SignedTransactionUnchecked,
19};
20use mirai_annotations::*;
21use serde::{Deserialize, Serialize};
22use std::collections::BTreeMap;
23
24#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
25pub enum BlockType {
26 Proposal {
27 payload: Payload,
29 author: Author,
32 },
33 NilBlock,
36 Genesis,
42}
43
44#[derive(Deserialize)]
45pub enum BlockTypeUnchecked {
46 Proposal {
47 payload: Vec<SignedTransactionUnchecked>,
48 author: Author,
49 },
50 NilBlock,
51 Genesis,
52}
53
54impl From<BlockTypeUnchecked> for BlockType {
55 fn from(t: BlockTypeUnchecked) -> Self {
56 match t {
57 BlockTypeUnchecked::Proposal { payload, author } => {
58 Self::Proposal {
59 payload: payload.into_iter().map(Into::into).collect(),
60 author,
61 }
62 }
63 BlockTypeUnchecked::NilBlock => Self::NilBlock,
64 BlockTypeUnchecked::Genesis => Self::Genesis,
65 }
66 }
67}
68
69#[derive(
70 Deserialize,
71 Serialize,
72 Clone,
73 Debug,
74 PartialEq,
75 Eq,
76 CryptoHasher,
77 BCSCryptoHash,
78)]
79pub struct BlockData {
83 epoch: u64,
86 round: Round,
89 timestamp_usecs: u64,
109 quorum_cert: QuorumCert,
112 block_type: BlockType,
114}
115
116#[derive(Deserialize)]
117pub struct BlockDataUnchecked {
118 pub epoch: u64,
119 pub round: Round,
120 pub timestamp_usecs: u64,
121 pub quorum_cert: QuorumCertUnchecked,
122 pub block_type: BlockTypeUnchecked,
123}
124
125impl From<BlockDataUnchecked> for BlockData {
126 fn from(b: BlockDataUnchecked) -> Self {
127 Self {
128 epoch: b.epoch,
129 round: b.round,
130 timestamp_usecs: b.timestamp_usecs,
131 quorum_cert: b.quorum_cert.into(),
132 block_type: b.block_type.into(),
133 }
134 }
135}
136
137impl BlockData {
138 pub fn author(&self) -> Option<Author> {
139 if let BlockType::Proposal { author, .. } = self.block_type {
140 Some(author)
141 } else {
142 None
143 }
144 }
145
146 pub fn block_type(&self) -> &BlockType { &self.block_type }
147
148 pub fn epoch(&self) -> u64 { self.epoch }
149
150 pub fn parent_id(&self) -> HashValue {
151 self.quorum_cert.certified_block().id()
152 }
153
154 pub fn payload(&self) -> Option<&Payload> {
155 if let BlockType::Proposal { payload, .. } = &self.block_type {
156 Some(payload)
157 } else {
158 None
159 }
160 }
161
162 pub fn round(&self) -> Round { self.round }
163
164 pub fn timestamp_usecs(&self) -> u64 { self.timestamp_usecs }
165
166 pub fn quorum_cert(&self) -> &QuorumCert { &self.quorum_cert }
167
168 pub fn is_genesis_block(&self) -> bool {
169 matches!(self.block_type, BlockType::Genesis)
170 }
171
172 pub fn is_nil_block(&self) -> bool {
173 matches!(self.block_type, BlockType::NilBlock)
174 }
175
176 pub fn vrf_round_seed(&self, seed: &[u8]) -> Vec<u8> {
177 let mut round_seed = seed.to_vec();
178 let leader_round = self.round.saturating_add(1) / 3;
182 round_seed.extend_from_slice(&leader_round.to_be_bytes());
183 round_seed
184 }
185
186 pub fn new_genesis_from_ledger_info(ledger_info: &LedgerInfo) -> Self {
187 assert!(ledger_info.ends_epoch());
188 let ancestor = BlockInfo::new(
189 ledger_info.epoch(),
190 0, HashValue::zero(), ledger_info.transaction_accumulator_hash(),
193 ledger_info.version(),
194 ledger_info.timestamp_usecs(),
195 None,
196 ledger_info.pivot_decision().cloned(),
197 );
198
199 let genesis_quorum_cert = QuorumCert::new(
203 VoteData::new(ancestor.clone(), ancestor.clone()),
204 LedgerInfoWithSignatures::new(
205 LedgerInfo::new(ancestor, HashValue::zero()),
206 BTreeMap::new(),
207 ),
208 );
209
210 BlockData::new_genesis(
211 ledger_info.timestamp_usecs(),
212 genesis_quorum_cert,
213 )
214 }
215
216 #[cfg(any(test, feature = "fuzzing"))]
217 pub fn new_for_testing(
220 epoch: u64, round: Round, timestamp_usecs: u64,
221 quorum_cert: QuorumCert, block_type: BlockType,
222 ) -> Self {
223 Self {
224 epoch,
225 round,
226 timestamp_usecs,
227 quorum_cert,
228 block_type,
229 }
230 }
231
232 pub fn new_genesis(timestamp_usecs: u64, quorum_cert: QuorumCert) -> Self {
233 assume!(quorum_cert.certified_block().epoch() < u64::max_value()); Self {
235 epoch: quorum_cert.certified_block().epoch() + 1,
236 round: 0,
237 timestamp_usecs,
238 quorum_cert,
239 block_type: BlockType::Genesis,
240 }
241 }
242
243 pub fn new_nil(round: Round, quorum_cert: QuorumCert) -> Self {
244 assume!(
248 quorum_cert.certified_block().timestamp_usecs() < u64::max_value()
249 ); let timestamp_usecs = quorum_cert.certified_block().timestamp_usecs();
251
252 Self {
253 epoch: quorum_cert.certified_block().epoch(),
254 round,
255 timestamp_usecs,
256 quorum_cert,
257 block_type: BlockType::NilBlock,
258 }
259 }
260
261 pub fn new_proposal(
262 payload: Payload, author: Author, round: Round, timestamp_usecs: u64,
263 quorum_cert: QuorumCert,
264 ) -> Self {
265 Self {
266 epoch: quorum_cert.certified_block().epoch(),
267 round,
268 timestamp_usecs,
269 quorum_cert,
270 block_type: BlockType::Proposal { payload, author },
271 }
272 }
273}