1use crate::hash::CryptoHash;
2use crate::merkle::MerklePath;
3use crate::sharding::{
4 ReceiptProof, ShardChunk, ShardChunkHeader, ShardChunkHeaderV1, ShardChunkV1,
5};
6use crate::types::{BlockHeight, EpochId, ShardId, StateRoot, StateRootNode};
7use borsh::{BorshDeserialize, BorshSerialize};
8use std::sync::Arc;
9use unc_primitives_core::types::EpochHeight;
10
11#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize)]
12pub struct ReceiptProofResponse(pub CryptoHash, pub Arc<Vec<ReceiptProof>>);
13
14#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize)]
15pub struct RootProof(pub CryptoHash, pub MerklePath);
16
17#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize)]
18pub struct StateHeaderKey(pub ShardId, pub CryptoHash);
19
20#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize)]
21pub struct StatePartKey(pub CryptoHash, pub ShardId, pub u64 );
22
23#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
24pub struct ShardStateSyncResponseHeaderV1 {
25 pub chunk: ShardChunkV1,
26 pub chunk_proof: MerklePath,
27 pub prev_chunk_header: Option<ShardChunkHeaderV1>,
28 pub prev_chunk_proof: Option<MerklePath>,
29 pub incoming_receipts_proofs: Vec<ReceiptProofResponse>,
30 pub root_proofs: Vec<Vec<RootProof>>,
31 pub state_root_node: StateRootNode,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
35pub struct ShardStateSyncResponseHeaderV2 {
36 pub chunk: ShardChunk,
37 pub chunk_proof: MerklePath,
38 pub prev_chunk_header: Option<ShardChunkHeader>,
39 pub prev_chunk_proof: Option<MerklePath>,
40 pub incoming_receipts_proofs: Vec<ReceiptProofResponse>,
41 pub root_proofs: Vec<Vec<RootProof>>,
42 pub state_root_node: StateRootNode,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
46pub enum CachedParts {
47 AllParts,
48 NoParts,
49 BitArray(BitArray),
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
57pub struct BitArray {
58 data: Vec<u8>,
59 capacity: u64,
60}
61
62impl BitArray {
63 pub fn new(capacity: u64) -> Self {
64 let num_bytes = (capacity + 7) / 8;
65 Self { data: vec![0; num_bytes as usize], capacity }
66 }
67
68 pub fn set_bit(&mut self, bit: u64) {
69 assert!(bit < self.capacity);
70 self.data[(bit / 8) as usize] |= 1 << (bit % 8);
71 }
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
75pub enum ShardStateSyncResponseHeader {
76 V1(ShardStateSyncResponseHeaderV1),
77 V2(ShardStateSyncResponseHeaderV2),
78}
79
80impl ShardStateSyncResponseHeader {
81 #[inline]
82 pub fn take_chunk(self) -> ShardChunk {
83 match self {
84 Self::V1(header) => ShardChunk::V1(header.chunk),
85 Self::V2(header) => header.chunk,
86 }
87 }
88
89 #[inline]
90 pub fn cloned_chunk(&self) -> ShardChunk {
91 match self {
92 Self::V1(header) => ShardChunk::V1(header.chunk.clone()),
93 Self::V2(header) => header.chunk.clone(),
94 }
95 }
96
97 #[inline]
98 pub fn cloned_prev_chunk_header(&self) -> Option<ShardChunkHeader> {
99 match self {
100 Self::V1(header) => header.prev_chunk_header.clone().map(ShardChunkHeader::V1),
101 Self::V2(header) => header.prev_chunk_header.clone(),
102 }
103 }
104
105 #[inline]
106 pub fn chunk_height_included(&self) -> BlockHeight {
107 match self {
108 Self::V1(header) => header.chunk.header.height_included,
109 Self::V2(header) => header.chunk.height_included(),
110 }
111 }
112
113 #[inline]
114 pub fn chunk_prev_state_root(&self) -> StateRoot {
115 match self {
116 Self::V1(header) => header.chunk.header.inner.prev_state_root,
117 Self::V2(header) => header.chunk.prev_state_root(),
118 }
119 }
120
121 #[inline]
122 pub fn chunk_proof(&self) -> &MerklePath {
123 match self {
124 Self::V1(header) => &header.chunk_proof,
125 Self::V2(header) => &header.chunk_proof,
126 }
127 }
128
129 #[inline]
130 pub fn prev_chunk_proof(&self) -> &Option<MerklePath> {
131 match self {
132 Self::V1(header) => &header.prev_chunk_proof,
133 Self::V2(header) => &header.prev_chunk_proof,
134 }
135 }
136
137 #[inline]
138 pub fn incoming_receipts_proofs(&self) -> &[ReceiptProofResponse] {
139 match self {
140 Self::V1(header) => &header.incoming_receipts_proofs,
141 Self::V2(header) => &header.incoming_receipts_proofs,
142 }
143 }
144
145 #[inline]
146 pub fn root_proofs(&self) -> &[Vec<RootProof>] {
147 match self {
148 Self::V1(header) => &header.root_proofs,
149 Self::V2(header) => &header.root_proofs,
150 }
151 }
152
153 #[inline]
154 pub fn state_root_node(&self) -> &StateRootNode {
155 match self {
156 Self::V1(header) => &header.state_root_node,
157 Self::V2(header) => &header.state_root_node,
158 }
159 }
160
161 pub fn num_state_parts(&self) -> u64 {
162 get_num_state_parts(self.state_root_node().memory_usage)
163 }
164}
165
166#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
167pub struct ShardStateSyncResponseV1 {
168 pub header: Option<ShardStateSyncResponseHeaderV1>,
169 pub part: Option<(u64, Vec<u8>)>,
170}
171
172#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
173pub struct ShardStateSyncResponseV2 {
174 pub header: Option<ShardStateSyncResponseHeaderV2>,
175 pub part: Option<(u64, Vec<u8>)>,
176}
177
178#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
179pub struct ShardStateSyncResponseV3 {
180 pub header: Option<ShardStateSyncResponseHeaderV2>,
181 pub part: Option<(u64, Vec<u8>)>,
182 pub cached_parts: Option<CachedParts>,
185 pub can_generate: bool,
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
191pub enum ShardStateSyncResponse {
192 V1(ShardStateSyncResponseV1),
193 V2(ShardStateSyncResponseV2),
194 V3(ShardStateSyncResponseV3),
195}
196
197impl ShardStateSyncResponse {
198 pub fn part_id(&self) -> Option<u64> {
199 match self {
200 Self::V1(response) => response.part_id(),
201 Self::V2(response) => response.part.as_ref().map(|(part_id, _)| *part_id),
202 Self::V3(response) => response.part.as_ref().map(|(part_id, _)| *part_id),
203 }
204 }
205
206 pub fn take_header(self) -> Option<ShardStateSyncResponseHeader> {
207 match self {
208 Self::V1(response) => response.header.map(ShardStateSyncResponseHeader::V1),
209 Self::V2(response) => response.header.map(ShardStateSyncResponseHeader::V2),
210 Self::V3(response) => response.header.map(ShardStateSyncResponseHeader::V2),
211 }
212 }
213
214 pub fn part(&self) -> &Option<(u64, Vec<u8>)> {
215 match self {
216 Self::V1(response) => &response.part,
217 Self::V2(response) => &response.part,
218 Self::V3(response) => &response.part,
219 }
220 }
221
222 pub fn take_part(self) -> Option<(u64, Vec<u8>)> {
223 match self {
224 Self::V1(response) => response.part,
225 Self::V2(response) => response.part,
226 Self::V3(response) => response.part,
227 }
228 }
229
230 pub fn can_generate(&self) -> bool {
231 match self {
232 Self::V1(_response) => false,
233 Self::V2(_response) => false,
234 Self::V3(response) => response.can_generate,
235 }
236 }
237
238 pub fn cached_parts(&self) -> &Option<CachedParts> {
239 match self {
240 Self::V1(_response) => &None,
241 Self::V2(_response) => &None,
242 Self::V3(response) => &response.cached_parts,
243 }
244 }
245}
246
247impl ShardStateSyncResponseV1 {
248 pub fn part_id(&self) -> Option<u64> {
249 self.part.as_ref().map(|(part_id, _)| *part_id)
250 }
251}
252
253pub const STATE_PART_MEMORY_LIMIT: bytesize::ByteSize = bytesize::ByteSize(30 * bytesize::MIB);
254
255pub fn get_num_state_parts(memory_usage: u64) -> u64 {
256 (memory_usage + STATE_PART_MEMORY_LIMIT.as_u64() - 1) / STATE_PART_MEMORY_LIMIT.as_u64()
257}
258
259#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
260pub enum StateSyncDumpProgress {
262 AllDumped {
266 epoch_id: EpochId,
268 epoch_height: EpochHeight,
269 },
270 InProgress {
272 epoch_id: EpochId,
274 epoch_height: EpochHeight,
275 sync_hash: CryptoHash,
278 },
279}
280
281#[cfg(test)]
282mod tests {
283 use crate::state_sync::{get_num_state_parts, STATE_PART_MEMORY_LIMIT};
284
285 #[test]
286 fn test_get_num_state_parts() {
287 assert_eq!(get_num_state_parts(0), 0);
288 assert_eq!(get_num_state_parts(1), 1);
289 assert_eq!(get_num_state_parts(STATE_PART_MEMORY_LIMIT.as_u64()), 1);
290 assert_eq!(get_num_state_parts(STATE_PART_MEMORY_LIMIT.as_u64() + 1), 2);
291 assert_eq!(get_num_state_parts(STATE_PART_MEMORY_LIMIT.as_u64() * 100), 100);
292 assert_eq!(get_num_state_parts(STATE_PART_MEMORY_LIMIT.as_u64() * 100 + 1), 101);
293 }
294}