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}