cfx_internal_common/
state_availability_boundary.rs1#[derive(Clone, Debug, MallocSizeOf)]
5pub struct StateAvailabilityBoundary {
6 #[debug(ignore)]
8 pub pivot_chain: Vec<H256>,
9
10 pub synced_state_height: u64,
11 pub full_state_start_height: Option<u64>,
14 pub full_state_space: Option<Space>,
17
18 pub lower_bound: u64,
23 pub upper_bound: u64,
25 pub optimistic_executed_height: Option<u64>,
30}
31
32impl StateAvailabilityBoundary {
33 pub fn new(
34 epoch_hash: H256, epoch_height: u64,
35 full_state_start_height: Option<u64>, full_state_space: Option<Space>,
36 ) -> Self {
37 Self {
38 pivot_chain: vec![epoch_hash],
39 synced_state_height: 0,
40 full_state_start_height,
41 full_state_space,
42 lower_bound: epoch_height,
43 upper_bound: epoch_height,
44 optimistic_executed_height: None,
45 }
46 }
47
48 pub fn check_availability(&self, height: u64, block_hash: &H256) -> bool {
50 (height == 0 || height != self.synced_state_height)
51 && self.lower_bound <= height
52 && height <= self.upper_bound
53 && {
54 let r = self.pivot_chain[(height - self.lower_bound) as usize]
55 == *block_hash;
56 if !r {
57 debug!(
58 "pivot_chain={:?} should be {:?} asked is {:?}",
59 self.pivot_chain,
60 self.pivot_chain[(height - self.lower_bound) as usize],
61 block_hash
62 );
63 }
64 r
65 }
66 }
67
68 pub fn check_read_availability(
69 &self, height: u64, block_hash: &H256, space: Option<Space>,
70 ) -> bool {
71 self.check_availability(height, block_hash)
72 || (height < self.lower_bound
73 && self.full_state_available(height, space))
74 }
75
76 fn full_state_available(&self, height: u64, space: Option<Space>) -> bool {
77 match self.full_state_start_height {
78 None => false,
80 Some(start_height) => {
82 height >= start_height && self.contains_space(&space)
83 }
84 }
85 }
86
87 pub fn contains_space(&self, space: &Option<Space>) -> bool {
88 match (space, &self.full_state_space) {
89 (_, None) => {
90 true
92 }
93 (None, Some(_)) => {
94 false
96 }
97 (Some(need_space), Some(kept_space)) => need_space == kept_space,
98 }
99 }
100
101 pub fn adjust_upper_bound(&mut self, executed_block: &BlockHeader) {
103 let next_index = (self.upper_bound - self.lower_bound + 1) as usize;
104 if next_index < self.pivot_chain.len()
105 && executed_block.height() == self.upper_bound + 1
106 && executed_block.hash() == self.pivot_chain[next_index]
107 {
108 self.upper_bound += 1;
109 }
110 }
111
112 pub fn set_synced_state_height(&mut self, synced_state_height: u64) {
115 self.synced_state_height = synced_state_height;
116 }
117
118 pub fn adjust_lower_bound(&mut self, new_lower_bound: u64) {
124 if self.upper_bound == 0 {
128 return;
129 }
130 assert!(self.lower_bound <= new_lower_bound);
131 assert!(
132 new_lower_bound <= self.upper_bound,
133 "however {} > {}, self {:?}",
134 new_lower_bound,
135 self.upper_bound,
136 self,
137 );
138 if self.synced_state_height != 0
139 && new_lower_bound > self.synced_state_height + REWARD_EPOCH_COUNT
140 {
141 self.synced_state_height = 0;
142 }
143 self.pivot_chain = self
144 .pivot_chain
145 .split_off((new_lower_bound - self.lower_bound) as usize);
146 self.lower_bound = new_lower_bound;
147 }
148}
149
150use cfx_parameters::consensus_internal::REWARD_EPOCH_COUNT;
151use cfx_types::{Space, H256};
152use derive_more::Debug;
153use malloc_size_of_derive::MallocSizeOf;
154use primitives::BlockHeader;