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}