1use crate::{
9 account_config, contract_event::ContractEvent, epoch_state::EpochState,
10 event::EventKey, on_chain_config::ValidatorSet, transaction::Version,
11};
12use anyhow::Result;
13use cfx_types::H256;
14use diem_crypto::hash::HashValue;
15#[cfg(any(test, feature = "fuzzing"))]
16use diem_crypto::hash::ACCUMULATOR_PLACEHOLDER_HASH;
17use diem_crypto_derive::{BCSCryptoHash, CryptoHasher};
18#[cfg(any(test, feature = "fuzzing"))]
19use proptest_derive::Arbitrary;
20use serde::{Deserialize, Serialize};
21use std::fmt::{Display, Formatter};
22
23pub type Round = u64;
26pub type View = u64;
27
28pub const GENESIS_EPOCH: u64 = 0;
30pub const GENESIS_ROUND: Round = 0;
31pub const GENESIS_VERSION: Version = 0;
32pub const GENESIS_TIMESTAMP_USECS: u64 = 0;
33
34#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
38#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
39pub struct BlockInfo {
40 epoch: u64,
43 round: Round,
46 id: HashValue,
48 executed_state_id: HashValue,
50 version: Version,
52 timestamp_usecs: u64,
54 next_epoch_state: Option<EpochState>,
56 pivot: Option<PivotBlockDecision>,
60}
61
62impl BlockInfo {
63 pub fn new(
64 epoch: u64, round: Round, id: HashValue, _executed_state_id: HashValue,
65 version: Version, timestamp_usecs: u64,
66 next_epoch_state: Option<EpochState>,
67 pivot: Option<PivotBlockDecision>,
68 ) -> Self {
69 Self {
70 epoch,
71 round,
72 id,
73 executed_state_id: Default::default(),
75 version,
76 timestamp_usecs,
77 next_epoch_state,
78 pivot,
79 }
80 }
81
82 pub fn empty() -> Self {
83 Self {
84 epoch: 0,
85 round: 0,
86 id: HashValue::zero(),
87 executed_state_id: HashValue::zero(),
88 version: 0,
89 timestamp_usecs: 0,
90 next_epoch_state: None,
91 pivot: None,
92 }
93 }
94
95 #[cfg(any(test, feature = "fuzzing"))]
96 pub fn random(round: Round) -> Self {
97 Self {
98 epoch: 1,
99 round,
100 id: HashValue::zero(),
101 executed_state_id: HashValue::zero(),
102 version: 0,
103 timestamp_usecs: 0,
104 next_epoch_state: None,
105 pivot: None,
106 }
107 }
108
109 pub fn genesis(
122 genesis_state_root_hash: HashValue, validator_set: ValidatorSet,
123 ) -> Self {
124 Self {
125 epoch: GENESIS_EPOCH,
126 round: GENESIS_ROUND,
127 id: HashValue::zero(),
128 executed_state_id: genesis_state_root_hash,
129 version: GENESIS_VERSION,
130 timestamp_usecs: GENESIS_TIMESTAMP_USECS,
131 next_epoch_state: Some(EpochState::new(
132 1,
133 (&validator_set).into(),
134 vec![],
136 )),
137 pivot: None,
138 }
139 }
140
141 #[cfg(any(test, feature = "fuzzing"))]
144 pub fn mock_genesis(validator_set: Option<ValidatorSet>) -> Self {
145 let validator_set = validator_set.unwrap_or_else(ValidatorSet::empty);
146 Self::genesis(*ACCUMULATOR_PLACEHOLDER_HASH, validator_set)
147 }
148
149 pub fn next_block_epoch(&self) -> u64 {
151 self.next_epoch_state().map_or(self.epoch(), |e| e.epoch)
152 }
153
154 pub fn epoch(&self) -> u64 { self.epoch }
155
156 pub fn executed_state_id(&self) -> HashValue { self.executed_state_id }
157
158 pub fn has_reconfiguration(&self) -> bool {
159 self.next_epoch_state.is_some()
160 }
161
162 pub fn id(&self) -> HashValue { self.id }
163
164 pub fn next_epoch_state(&self) -> Option<&EpochState> {
165 self.next_epoch_state.as_ref()
166 }
167
168 pub fn round(&self) -> Round { self.round }
169
170 pub fn timestamp_usecs(&self) -> u64 { self.timestamp_usecs }
171
172 pub fn version(&self) -> Version { self.version }
173
174 pub fn pivot_decision(&self) -> Option<&PivotBlockDecision> {
175 self.pivot.as_ref()
176 }
177}
178
179impl Display for BlockInfo {
180 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
181 write!(
182 f,
183 "BlockInfo: [epoch: {}, round: {}, id: {}, executed_state_id: {}, version: {}, timestamp (us): {}, next_epoch_state: {}, pivot: {:?}]",
184 self.epoch(),
185 self.round(),
186 self.id(),
187 self.executed_state_id(),
188 self.version(),
189 self.timestamp_usecs(),
190 self.next_epoch_state.as_ref().map_or("None".to_string(), |epoch_state| format!("{}", epoch_state)),
191 self.pivot,
192 )
193 }
194}
195
196#[derive(
197 Clone,
198 Debug,
199 Default,
200 Hash,
201 Eq,
202 PartialEq,
203 Serialize,
204 Deserialize,
205 BCSCryptoHash,
206 CryptoHasher,
207)]
208#[serde(rename_all = "camelCase")]
209pub struct PivotBlockDecision {
210 pub height: u64,
211 pub block_hash: H256,
212}
213
214impl PivotBlockDecision {
215 pub fn pivot_select_event_key() -> EventKey {
216 EventKey::new_from_address(
217 &account_config::pivot_chain_select_address(),
218 2,
219 )
220 }
221
222 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
223 bcs::from_bytes(bytes).map_err(Into::into)
224 }
225
226 pub fn to_event(&self) -> ContractEvent {
227 ContractEvent::new(
228 Self::pivot_select_event_key(),
229 bcs::to_bytes(&self).unwrap(),
230 )
231 }
232}
233
234#[cfg(any(test, feature = "fuzzing"))]
235use proptest::prelude::*;
236
237#[cfg(any(test, feature = "fuzzing"))]
238impl proptest::arbitrary::Arbitrary for PivotBlockDecision {
239 type Parameters = ();
240 type Strategy = BoxedStrategy<Self>;
241
242 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
243 any::<u8>()
244 .prop_map(|_seed| PivotBlockDecision {
245 height: 0,
246 block_hash: H256::zero(),
247 })
248 .boxed()
249 }
250}