hotshot_query_service/node/
data_source.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
13//! Data for the [`node`](super) API.
14//!
15//! This module is just an alternative view of the same data provided by the
16//! [`availability`](crate::availability) API. It provides more insight into what data the node
17//! actually has at present, as opposed to trying to present a perfect view of an abstract chain,
18//! fetching data from other sources as needed. It is also more liberal with provided aggregate
19//! counts and statistics which may be inaccurate if data is missing.
20//!
21//! Due to this relationship with the availability module, this module has its own [data source
22//! trait](`NodeDataSource`) but not its own update trait. The node data source is expected to read
23//! its data from the same underlying database as the availability API, and as such the data is
24//! updated implicitly via the [availability API update
25//! trait](crate::availability::UpdateAvailabilityData).
26
27use std::ops::RangeBounds;
28
29use async_trait::async_trait;
30use derivative::Derivative;
31use derive_more::From;
32use hotshot_types::{data::VidShare, traits::node_implementation::NodeType};
33
34use super::query_data::{BlockHash, BlockId, TimeWindowQueryData};
35use crate::{
36    Header, QueryResult,
37    availability::{NamespaceId, QueryableHeader},
38    node::SyncStatusQueryData,
39};
40
41#[derive(Derivative, From)]
42#[derivative(Copy(bound = ""), Debug(bound = ""))]
43pub enum WindowStart<Types: NodeType> {
44    #[from(ignore)]
45    Time(u64),
46    #[from(ignore)]
47    Height(u64),
48    Hash(BlockHash<Types>),
49}
50
51impl<Types: NodeType> Clone for WindowStart<Types> {
52    fn clone(&self) -> Self {
53        *self
54    }
55}
56
57#[async_trait]
58pub trait NodeDataSource<Types>
59where
60    Types: NodeType,
61    Header<Types>: QueryableHeader<Types>,
62{
63    async fn block_height(&self) -> QueryResult<usize>;
64    async fn count_transactions_in_range(
65        &self,
66        range: impl RangeBounds<usize> + Send,
67        namespace: Option<NamespaceId<Types>>,
68    ) -> QueryResult<usize>;
69    async fn payload_size_in_range(
70        &self,
71        range: impl RangeBounds<usize> + Send,
72        namespace: Option<NamespaceId<Types>>,
73    ) -> QueryResult<usize>;
74    async fn vid_share<ID>(&self, id: ID) -> QueryResult<VidShare>
75    where
76        ID: Into<BlockId<Types>> + Send + Sync;
77    async fn get_header_window(
78        &self,
79        start: impl Into<WindowStart<Types>> + Send + Sync,
80        end: u64,
81        limit: usize,
82    ) -> QueryResult<TimeWindowQueryData<Header<Types>>>;
83
84    /// Search the database for missing objects and generate a report.
85    ///
86    /// # Consistency
87    ///
88    /// Each [`SyncStatusRange`](super::query_data::SyncStatusRange) in the response accurately
89    /// describes the status of that range of objects at a recent point in time. (It is of course
90    /// impossible to consistently describe the status of the range _now_, as this method does not
91    /// require any lock to call, and thus the sync status could change immediately after being
92    /// checked.)
93    ///
94    /// It is not practical to scan the entire database for missing objects in a single atomic
95    /// transaction. Thus, it is possible that different ranges in the response reflect the state of
96    /// that portion of the database at different times. In other words, each range is an atomic
97    /// snapshot of a subset of the database, but there may never have been a time when the entire
98    /// database had the exact state represented by the collection of ranges in response, all at
99    /// once.
100    async fn sync_status(&self) -> QueryResult<SyncStatusQueryData>;
101
102    async fn count_transactions(&self) -> QueryResult<usize> {
103        self.count_transactions_in_range(0.., None).await
104    }
105
106    async fn payload_size(&self) -> QueryResult<usize> {
107        self.payload_size_in_range(0.., None).await
108    }
109}