cfxcore/consensus/consensus_graph/
onchain_blocks_provider.rs1use super::ConsensusGraph;
2
3use crate::errors::{invalid_params, Result as CoreResult};
4use cfxcore_errors::ProviderBlockError;
5
6use cfx_parameters::consensus::*;
7
8use cfx_types::H256;
9
10use primitives::{compute_block_number, BlockHashOrEpochNumber, EpochNumber};
11use std::cmp::min;
12
13impl ConsensusGraph {
14 pub fn block_count(&self) -> u64 {
21 self.inner.read_recursive().total_processed_block_count()
22 }
23
24 pub fn get_height_from_epoch_number(
26 &self, epoch_number: EpochNumber,
27 ) -> Result<u64, ProviderBlockError> {
28 Ok(match epoch_number {
29 EpochNumber::Earliest => 0,
30 EpochNumber::LatestCheckpoint => {
31 self.latest_checkpoint_epoch_number()
32 }
33 EpochNumber::LatestConfirmed => {
34 self.latest_confirmed_epoch_number()
35 }
36 EpochNumber::LatestMined => self.best_epoch_number(),
37 EpochNumber::LatestFinalized => {
38 self.latest_finalized_epoch_number()
39 }
40 EpochNumber::LatestState => self.best_executed_state_epoch_number(),
41 EpochNumber::Number(num) => {
42 let epoch_num = num;
43 if epoch_num > self.inner.read_recursive().best_epoch_number() {
44 return Err(ProviderBlockError::EpochNumberTooLarge);
45 }
46 epoch_num
47 }
48 })
49 }
50
51 pub fn get_block_epoch_number(&self, hash: &H256) -> Option<u64> {
52 if let Some(e) =
54 self.inner.read_recursive().get_block_epoch_number(hash)
55 {
56 return Some(e);
57 }
58
59 self.data_man.block_epoch_number(hash)
61 }
62
63 pub fn get_block_hashes_by_epoch(
64 &self, epoch_number: EpochNumber,
65 ) -> Result<Vec<H256>, ProviderBlockError> {
66 self.get_height_from_epoch_number(epoch_number)
67 .and_then(|height| {
68 self.inner.read_recursive().block_hashes_by_epoch(height)
69 })
70 }
71
72 pub fn get_block_hashes_by_epoch_or_block_hash(
73 &self, block_hash_or_epoch: BlockHashOrEpochNumber,
74 ) -> Result<Vec<H256>, ProviderBlockError> {
75 let hashes = match block_hash_or_epoch {
76 BlockHashOrEpochNumber::EpochNumber(e) => {
77 self.get_block_hashes_by_epoch(e)?
78 }
79 BlockHashOrEpochNumber::BlockHashWithOption {
80 hash: h,
81 require_pivot,
82 } => {
83 let _ = self
85 .data_manager()
86 .block_header_by_hash(&h)
87 .ok_or("block not found")?;
88
89 let e =
90 self.get_block_epoch_number(&h).ok_or("block not found")?;
91
92 let hashes = self.get_block_hashes_by_epoch(e.into())?;
93
94 let pivot_hash = *hashes.last().ok_or("inconsistent state")?;
98
99 if require_pivot.unwrap_or(true) && (h != pivot_hash) {
100 bail!(ProviderBlockError::Common(
101 "require_pivot check failed".into()
102 ));
103 }
104
105 hashes
106 }
107 };
108 Ok(hashes)
109 }
110
111 pub fn get_hash_from_epoch_number(
113 &self, epoch_number: EpochNumber,
114 ) -> Result<H256, ProviderBlockError> {
115 self.get_height_from_epoch_number(epoch_number)
116 .and_then(|height| {
117 self.inner
118 .read_recursive()
119 .get_pivot_hash_from_epoch_number(height)
120 })
121 }
122
123 pub fn get_skipped_block_hashes_by_epoch(
124 &self, epoch_number: EpochNumber,
125 ) -> Result<Vec<H256>, ProviderBlockError> {
126 self.get_height_from_epoch_number(epoch_number)
127 .and_then(|height| {
128 self.inner
129 .read_recursive()
130 .skipped_block_hashes_by_epoch(height)
131 })
132 }
133
134 pub fn get_block_epoch_number_with_pivot_check(
135 &self, hash: &H256, require_pivot: bool,
136 ) -> CoreResult<u64> {
137 let inner = &*self.inner.read();
138 let epoch_number =
140 inner.get_block_epoch_number(&hash).ok_or(invalid_params(
141 "epoch parameter",
142 format!("block's epoch number is not found: {:?}", hash),
143 ))?;
144
145 if require_pivot {
146 if let Err(..) =
147 inner.check_block_pivot_assumption(&hash, epoch_number)
148 {
149 bail!(invalid_params(
150 "epoch parameter",
151 format!(
152 "should receive a pivot block hash, receives: {:?}",
153 hash
154 ),
155 ))
156 }
157 }
158 Ok(epoch_number)
159 }
160
161 pub fn get_block_number(
162 &self, block_hash: &H256,
163 ) -> Result<Option<u64>, String> {
164 let inner = self.inner.read_recursive();
165
166 let epoch_number = match inner
167 .get_block_epoch_number(block_hash)
168 .or_else(|| self.data_man.block_epoch_number(&block_hash))
169 {
170 None => return Ok(None),
171 Some(epoch_number) => epoch_number,
172 };
173
174 let blocks = match self
175 .get_block_hashes_by_epoch(EpochNumber::Number(epoch_number))
176 .ok()
177 .or_else(|| {
178 self.data_man
179 .executed_epoch_set_hashes_from_db(epoch_number)
180 }) {
181 None => return Ok(None),
182 Some(hashes) => hashes,
183 };
184
185 let epoch_hash = blocks.last().expect("Epoch not empty");
186
187 let start_block_number =
188 match self.data_man.get_epoch_execution_context(&epoch_hash) {
189 None => return Ok(None),
190 Some(ctx) => ctx.start_block_number,
191 };
192
193 let index_of_block = match blocks.iter().position(|x| x == block_hash) {
194 None => return Ok(None),
195 Some(index) => index as u64,
196 };
197
198 return Ok(Some(compute_block_number(
199 start_block_number,
200 index_of_block,
201 )));
202 }
203
204 pub fn validate_stated_epoch(
205 &self, epoch_number: &EpochNumber,
206 ) -> Result<(), String> {
207 match epoch_number {
208 EpochNumber::LatestMined => {
209 return Err("Latest mined epoch is not executed".into());
210 }
211 EpochNumber::Number(num) => {
212 let latest_state_epoch =
213 self.best_executed_state_epoch_number();
214 if *num > latest_state_epoch {
215 return Err(format!("Specified epoch {} is not executed, the latest state epoch is {}", num, latest_state_epoch));
216 }
217 }
218 _ => {}
219 }
220
221 Ok(())
222 }
223
224 pub fn best_executed_state_epoch_number(&self) -> u64 {
228 let state_upper_bound =
229 self.data_man.state_availability_boundary.read().upper_bound;
230 let best_epoch_number = self.best_info.read().best_epoch_number;
233 let deferred_state_height =
234 if best_epoch_number < DEFERRED_STATE_EPOCH_COUNT {
235 0
236 } else {
237 best_epoch_number - DEFERRED_STATE_EPOCH_COUNT + 1
238 };
239 min(state_upper_bound, deferred_state_height)
245 }
246}