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 + 1) / 3;
181 round_seed.extend_from_slice(&leader_round.to_be_bytes());
182 round_seed
183 }
184
185 pub fn new_genesis_from_ledger_info(ledger_info: &LedgerInfo) -> Self {
186 assert!(ledger_info.ends_epoch());
187 let ancestor = BlockInfo::new(
188 ledger_info.epoch(),
189 0, HashValue::zero(), ledger_info.transaction_accumulator_hash(),
192 ledger_info.version(),
193 ledger_info.timestamp_usecs(),
194 None,
195 ledger_info.pivot_decision().cloned(),
196 );
197
198 let genesis_quorum_cert = QuorumCert::new(
202 VoteData::new(ancestor.clone(), ancestor.clone()),
203 LedgerInfoWithSignatures::new(
204 LedgerInfo::new(ancestor, HashValue::zero()),
205 BTreeMap::new(),
206 ),
207 );
208
209 BlockData::new_genesis(
210 ledger_info.timestamp_usecs(),
211 genesis_quorum_cert,
212 )
213 }
214
215 #[cfg(any(test, feature = "fuzzing"))]
216 pub fn new_for_testing(
219 epoch: u64, round: Round, timestamp_usecs: u64,
220 quorum_cert: QuorumCert, block_type: BlockType,
221 ) -> Self {
222 Self {
223 epoch,
224 round,
225 timestamp_usecs,
226 quorum_cert,
227 block_type,
228 }
229 }
230
231 pub fn new_genesis(timestamp_usecs: u64, quorum_cert: QuorumCert) -> Self {
232 assume!(quorum_cert.certified_block().epoch() < u64::max_value()); Self {
234 epoch: quorum_cert.certified_block().epoch() + 1,
235 round: 0,
236 timestamp_usecs,
237 quorum_cert,
238 block_type: BlockType::Genesis,
239 }
240 }
241
242 pub fn new_nil(round: Round, quorum_cert: QuorumCert) -> Self {
243 assume!(
247 quorum_cert.certified_block().timestamp_usecs() < u64::max_value()
248 ); let timestamp_usecs = quorum_cert.certified_block().timestamp_usecs();
250
251 Self {
252 epoch: quorum_cert.certified_block().epoch(),
253 round,
254 timestamp_usecs,
255 quorum_cert,
256 block_type: BlockType::NilBlock,
257 }
258 }
259
260 pub fn new_proposal(
261 payload: Payload, author: Author, round: Round, timestamp_usecs: u64,
262 quorum_cert: QuorumCert,
263 ) -> Self {
264 Self {
265 epoch: quorum_cert.certified_block().epoch(),
266 round,
267 timestamp_usecs,
268 quorum_cert,
269 block_type: BlockType::Proposal { payload, author },
270 }
271 }
272}