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