1use crate::hash::CryptoHash;
2use crate::merkle::MerklePath;
3use crate::sharding::{
4 ReceiptProof, ShardChunk, ShardChunkHeader, ShardChunkHeaderV1, ShardChunkV1,
5};
6use crate::state_part::{StatePart, StatePartV0};
7use crate::types::{BlockHeight, EpochId, ShardId, StateRoot, StateRootNode};
8use borsh::{BorshDeserialize, BorshSerialize};
9use near_primitives_core::types::EpochHeight;
10use near_schema_checker_lib::ProtocolSchema;
11use std::sync::Arc;
12
13#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, ProtocolSchema)]
14pub struct ReceiptProofResponse(pub CryptoHash, pub Arc<Vec<ReceiptProof>>);
15
16#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, ProtocolSchema)]
17pub struct RootProof(pub CryptoHash, pub MerklePath);
18
19#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, ProtocolSchema)]
20pub struct StateHeaderKey(pub ShardId, pub CryptoHash);
21
22#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, ProtocolSchema)]
23pub struct StatePartKey(pub CryptoHash, pub ShardId, pub u64 );
24
25#[derive(
26 Copy, PartialEq, Eq, Clone, Debug, Hash, BorshSerialize, BorshDeserialize, ProtocolSchema,
27)]
28pub enum PartIdOrHeader {
29 Part { part_id: u64 },
30 Header,
31}
32
33impl Into<&'static str> for PartIdOrHeader {
34 fn into(self) -> &'static str {
35 match self {
36 PartIdOrHeader::Part { .. } => "part",
37 PartIdOrHeader::Header => "header",
38 }
39 }
40}
41
42#[derive(Copy, PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, ProtocolSchema)]
43pub enum StateRequestAckBody {
44 WillRespond,
45 Busy,
46 Error,
47}
48
49impl Into<&'static str> for StateRequestAckBody {
50 fn into(self) -> &'static str {
51 match self {
52 StateRequestAckBody::WillRespond => "will_respond",
53 StateRequestAckBody::Busy => "busy",
54 StateRequestAckBody::Error => "error",
55 }
56 }
57}
58
59#[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, ProtocolSchema)]
60pub struct StateRequestAck {
61 pub shard_id: ShardId,
63 pub sync_hash: CryptoHash,
65 pub part_id_or_header: PartIdOrHeader,
67 pub body: StateRequestAckBody,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
72pub struct ShardStateSyncResponseHeaderV1 {
73 pub chunk: ShardChunkV1,
74 pub chunk_proof: MerklePath,
75 pub prev_chunk_header: Option<ShardChunkHeaderV1>,
76 pub prev_chunk_proof: Option<MerklePath>,
77 pub incoming_receipts_proofs: Vec<ReceiptProofResponse>,
78 pub root_proofs: Vec<Vec<RootProof>>,
79 pub state_root_node: StateRootNode,
80}
81
82#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
92pub struct ShardStateSyncResponseHeaderV2 {
93 pub chunk: ShardChunk,
96 pub chunk_proof: MerklePath,
99 pub prev_chunk_header: Option<ShardChunkHeader>,
101 pub prev_chunk_proof: Option<MerklePath>,
104 pub incoming_receipts_proofs: Vec<ReceiptProofResponse>,
108 pub root_proofs: Vec<Vec<RootProof>>,
119 pub state_root_node: StateRootNode,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
125#[borsh(use_discriminant = true)]
126#[repr(u8)]
127pub enum CachedParts {
128 AllParts = 0,
129 NoParts = 1,
130 BitArray(BitArray) = 2,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
138pub struct BitArray {
139 data: Vec<u8>,
140 capacity: u64,
141}
142
143impl BitArray {
144 pub fn new(capacity: u64) -> Self {
145 let num_bytes = (capacity + 7) / 8;
146 Self { data: vec![0; num_bytes as usize], capacity }
147 }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
151#[borsh(use_discriminant = true)]
152#[repr(u8)]
153#[allow(clippy::large_enum_variant)]
154pub enum ShardStateSyncResponseHeader {
155 V1(ShardStateSyncResponseHeaderV1) = 0,
156 V2(ShardStateSyncResponseHeaderV2) = 1,
157}
158
159impl ShardStateSyncResponseHeader {
160 #[inline]
161 pub fn take_chunk(self) -> ShardChunk {
162 match self {
163 Self::V1(header) => ShardChunk::V1(header.chunk),
164 Self::V2(header) => header.chunk,
165 }
166 }
167
168 #[inline]
169 pub fn cloned_chunk(&self) -> ShardChunk {
170 match self {
171 Self::V1(header) => ShardChunk::V1(header.chunk.clone()),
172 Self::V2(header) => header.chunk.clone(),
173 }
174 }
175
176 #[inline]
177 pub fn cloned_prev_chunk_header(&self) -> Option<ShardChunkHeader> {
178 match self {
179 Self::V1(header) => header.prev_chunk_header.clone().map(ShardChunkHeader::V1),
180 Self::V2(header) => header.prev_chunk_header.clone(),
181 }
182 }
183
184 #[inline]
185 pub fn chunk_height_included(&self) -> BlockHeight {
186 match self {
187 Self::V1(header) => header.chunk.header.height_included,
188 Self::V2(header) => header.chunk.height_included(),
189 }
190 }
191
192 #[inline]
193 pub fn chunk_prev_state_root(&self) -> StateRoot {
194 match self {
195 Self::V1(header) => header.chunk.header.inner.prev_state_root,
196 Self::V2(header) => header.chunk.prev_state_root(),
197 }
198 }
199
200 #[inline]
201 pub fn chunk_proof(&self) -> &MerklePath {
202 match self {
203 Self::V1(header) => &header.chunk_proof,
204 Self::V2(header) => &header.chunk_proof,
205 }
206 }
207
208 #[inline]
209 pub fn prev_chunk_proof(&self) -> &Option<MerklePath> {
210 match self {
211 Self::V1(header) => &header.prev_chunk_proof,
212 Self::V2(header) => &header.prev_chunk_proof,
213 }
214 }
215
216 #[inline]
217 pub fn incoming_receipts_proofs(&self) -> &[ReceiptProofResponse] {
218 match self {
219 Self::V1(header) => &header.incoming_receipts_proofs,
220 Self::V2(header) => &header.incoming_receipts_proofs,
221 }
222 }
223
224 #[inline]
225 pub fn root_proofs(&self) -> &[Vec<RootProof>] {
226 match self {
227 Self::V1(header) => &header.root_proofs,
228 Self::V2(header) => &header.root_proofs,
229 }
230 }
231
232 #[inline]
233 pub fn state_root_node(&self) -> &StateRootNode {
234 match self {
235 Self::V1(header) => &header.state_root_node,
236 Self::V2(header) => &header.state_root_node,
237 }
238 }
239
240 pub fn num_state_parts(&self) -> u64 {
241 get_num_state_parts(self.state_root_node().memory_usage)
242 }
243}
244
245#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
246pub struct ShardStateSyncResponseV1 {
247 pub header: Option<ShardStateSyncResponseHeaderV1>,
248 pub part: Option<(u64, Vec<u8>)>,
249}
250
251impl ShardStateSyncResponseV1 {
252 pub fn part_id(&self) -> Option<u64> {
253 self.part.as_ref().map(|(part_id, _)| *part_id)
254 }
255
256 pub fn payload_length(&self) -> Option<usize> {
257 self.part.as_ref().map(|(_, part)| part.len())
258 }
259}
260
261#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
262pub struct ShardStateSyncResponseV2 {
263 pub header: Option<ShardStateSyncResponseHeaderV2>,
264 pub part: Option<(u64, Vec<u8>)>,
265}
266
267#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
268pub struct ShardStateSyncResponseV3 {
269 pub header: Option<ShardStateSyncResponseHeaderV2>,
270 pub part: Option<(u64, Vec<u8>)>,
271 pub cached_parts: Option<CachedParts>,
272 pub can_generate: bool,
273}
274
275#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
277pub struct ShardStateSyncResponseV4 {
278 pub header: Option<ShardStateSyncResponseHeaderV2>,
279 pub part: Option<(u64, StatePart)>,
280}
281
282#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
283#[borsh(use_discriminant = true)]
284#[repr(u8)]
285pub enum ShardStateSyncResponse {
286 V1(ShardStateSyncResponseV1) = 0,
287 V2(ShardStateSyncResponseV2) = 1,
288 V3(ShardStateSyncResponseV3) = 2,
289 V4(ShardStateSyncResponseV4) = 3,
290}
291
292impl ShardStateSyncResponse {
293 pub fn new_from_header(header: Option<ShardStateSyncResponseHeaderV2>) -> Self {
294 Self::new_from_header_or_part(header, None)
295 }
296
297 pub fn new_from_part(part: Option<(u64, StatePart)>) -> Self {
298 Self::new_from_header_or_part(None, part)
299 }
300
301 fn new_from_header_or_part(
302 header: Option<ShardStateSyncResponseHeaderV2>,
303 part: Option<(u64, StatePart)>,
304 ) -> Self {
305 Self::V4(ShardStateSyncResponseV4 { header, part })
306 }
307
308 pub fn take_header(self) -> Option<ShardStateSyncResponseHeader> {
309 match self {
310 Self::V1(response) => response.header.map(ShardStateSyncResponseHeader::V1),
311 Self::V2(response) => response.header.map(ShardStateSyncResponseHeader::V2),
312 Self::V3(response) => response.header.map(ShardStateSyncResponseHeader::V2),
313 Self::V4(response) => response.header.map(ShardStateSyncResponseHeader::V2),
314 }
315 }
316
317 pub fn part_id(&self) -> Option<u64> {
318 match self {
319 Self::V1(response) => response.part.as_ref().map(|(part_id, _)| *part_id),
320 Self::V2(response) => response.part.as_ref().map(|(part_id, _)| *part_id),
321 Self::V3(response) => response.part.as_ref().map(|(part_id, _)| *part_id),
322 Self::V4(response) => response.part.as_ref().map(|(part_id, _)| *part_id),
323 }
324 }
325
326 pub fn take_part(self) -> Option<(u64, StatePart)> {
327 match self {
328 Self::V1(response) => {
329 response.part.map(|(idx, part)| (idx, StatePart::V0(StatePartV0(part))))
330 }
331 Self::V2(response) => {
332 response.part.map(|(idx, part)| (idx, StatePart::V0(StatePartV0(part))))
333 }
334 Self::V3(response) => {
335 response.part.map(|(idx, part)| (idx, StatePart::V0(StatePartV0(part))))
336 }
337 Self::V4(response) => response.part,
338 }
339 }
340
341 pub fn payload_length(&self) -> Option<usize> {
342 match self {
343 Self::V1(response) => response.part.as_ref().map(|(_, part)| part.len()),
344 Self::V2(response) => response.part.as_ref().map(|(_, part)| part.len()),
345 Self::V3(response) => response.part.as_ref().map(|(_, part)| part.len()),
346 Self::V4(response) => response.part.as_ref().map(|(_, part)| part.payload_length()),
347 }
348 }
349}
350
351pub const STATE_PART_MEMORY_LIMIT: bytesize::ByteSize = bytesize::ByteSize(30 * bytesize::MIB);
352
353pub fn get_num_state_parts(memory_usage: u64) -> u64 {
354 (memory_usage + STATE_PART_MEMORY_LIMIT.as_u64() - 1) / STATE_PART_MEMORY_LIMIT.as_u64()
355}
356
357#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, serde::Serialize, ProtocolSchema)]
358#[borsh(use_discriminant = true)]
359#[repr(u8)]
360pub enum StateSyncDumpProgress {
362 AllDumped {
366 epoch_id: EpochId,
368 epoch_height: EpochHeight,
369 } = 0,
370 Skipped { epoch_id: EpochId, epoch_height: EpochHeight } = 1,
372 InProgress {
374 epoch_id: EpochId,
376 epoch_height: EpochHeight,
377 sync_hash: CryptoHash,
380 } = 2,
381}
382
383#[cfg(test)]
384mod tests {
385 use crate::state_sync::{STATE_PART_MEMORY_LIMIT, get_num_state_parts};
386
387 #[test]
388 fn test_get_num_state_parts() {
389 assert_eq!(get_num_state_parts(0), 0);
390 assert_eq!(get_num_state_parts(1), 1);
391 assert_eq!(get_num_state_parts(STATE_PART_MEMORY_LIMIT.as_u64()), 1);
392 assert_eq!(get_num_state_parts(STATE_PART_MEMORY_LIMIT.as_u64() + 1), 2);
393 assert_eq!(get_num_state_parts(STATE_PART_MEMORY_LIMIT.as_u64() * 100), 100);
394 assert_eq!(get_num_state_parts(STATE_PART_MEMORY_LIMIT.as_u64() * 100 + 1), 101);
395 }
396}