hotshot_query_service/node/query_data.rs
1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the HotShot Query Service library.
3//
4// This program is free software: you can redistribute it and/or modify it under the terms of the GNU
5// General Public License as published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
8// even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9// General Public License for more details.
10// You should have received a copy of the GNU General Public License along with this program. If not,
11// see <https://www.gnu.org/licenses/>.
12
13use std::ops::{Bound, RangeBounds};
14
15use derivative::Derivative;
16use serde::{Deserialize, Serialize};
17
18pub use crate::availability::{BlockHash, BlockId};
19use crate::types::HeightIndexed;
20
21/// A status of a set of resources, regarding its presence in the database.
22///
23/// A single resource or range of consecutive resources may be either:
24/// * Present in the database
25/// * Missing from the database, but will eventually be recovered via asynchronous fetching
26/// * Pruned, meaning it is missing, but intentionally so, and will not be fetched
27#[derive(
28 Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize,
29)]
30pub enum SyncStatus {
31 #[default]
32 Present,
33 Missing,
34 Pruned,
35}
36
37/// The [`SyncStatus`] describing a range of consecutive objects of a single type.
38#[derive(
39 Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize,
40)]
41pub struct SyncStatusRange {
42 /// The inclusive starting height for the range.
43 pub start: usize,
44 /// The exclusive ending height for the range.
45 pub end: usize,
46 /// The sync status for objects in this range.
47 pub status: SyncStatus,
48}
49
50impl RangeBounds<usize> for SyncStatusRange {
51 fn start_bound(&self) -> Bound<&usize> {
52 Bound::Included(&self.start)
53 }
54
55 fn end_bound(&self) -> Bound<&usize> {
56 Bound::Excluded(&self.end)
57 }
58}
59
60/// A summary of the [`SyncStatus`] for a single resource (e.g. blocks, or leaves).
61#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
62pub struct ResourceSyncStatus {
63 /// The number of missing (not including pruned) objects for this resource.
64 pub missing: usize,
65
66 /// An ordered list of contiguous ranges of objects of this type with the same sync status.
67 pub ranges: Vec<SyncStatusRange>,
68}
69
70impl ResourceSyncStatus {
71 pub fn is_fully_synced(&self) -> bool {
72 self.missing == 0
73 }
74
75 /// Extend this [`ResourceSyncStatus`] to additionally cover the range covered by `other`.
76 pub fn extend(&mut self, other: Self) {
77 self.missing += other.missing;
78
79 let mut ranges = other.ranges.into_iter();
80
81 // Check if the last range of `self` and the first range of `other` can be combined.
82 if let Some(last) = self.ranges.last_mut()
83 && let Some(next) = ranges.next()
84 {
85 if last.status == next.status && last.end == next.start {
86 last.end = next.end;
87 } else {
88 self.ranges.push(next);
89 }
90 }
91
92 self.ranges.extend(ranges);
93 }
94}
95
96/// [`SyncStatus`] for the entire database.
97#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
98pub struct SyncStatusQueryData {
99 /// Summary of the [`SyncStatus`] of all blocks.
100 pub blocks: ResourceSyncStatus,
101 /// Summary of the [`SyncStatus`] of all leaves.
102 pub leaves: ResourceSyncStatus,
103 /// Summary of the [`SyncStatus`] of all VID common objects.
104 pub vid_common: ResourceSyncStatus,
105 /// Summary of the [`SyncStatus`] of all VID shares.
106 pub vid_shares: ResourceSyncStatus,
107
108 /// The height of the last pruned object.
109 ///
110 /// Objects below this height are intentionally missing and will never be recovered (unless
111 /// pruning settings are changed.)
112 pub pruned_height: Option<usize>,
113}
114
115impl SyncStatusQueryData {
116 pub fn is_fully_synced(&self) -> bool {
117 self.blocks.is_fully_synced()
118 && self.leaves.is_fully_synced()
119 && self.vid_common.is_fully_synced()
120 && self.vid_shares.is_fully_synced()
121 }
122}
123
124/// Response to a `/:resource/window` query.
125#[derive(Clone, Debug, Derivative, PartialEq, Eq, Serialize, Deserialize)]
126#[derivative(Default(bound = ""))]
127pub struct TimeWindowQueryData<T> {
128 pub window: Vec<T>,
129 pub prev: Option<T>,
130 pub next: Option<T>,
131}
132
133impl<T: HeightIndexed> TimeWindowQueryData<T> {
134 /// The block height of the block that starts the window.
135 ///
136 /// If the window is empty, this is the height of the block that ends the window.
137 pub fn from(&self) -> Option<u64> {
138 self.window
139 .first()
140 .or(self.next.as_ref())
141 .map(|t| t.height())
142 }
143}
144
145#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
146pub struct Limits {
147 pub window_limit: usize,
148}