hotshot_query_service/availability/
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
13use std::{
14    cmp::Ordering,
15    ops::{Bound, RangeBounds},
16};
17
18use async_trait::async_trait;
19use derivative::Derivative;
20use derive_more::{Display, From};
21use futures::{
22    future::Future,
23    stream::{BoxStream, StreamExt},
24};
25use hotshot_types::{
26    data::{VidCommitment, VidShare},
27    simple_certificate::CertificatePair,
28    traits::node_implementation::NodeType,
29};
30
31use super::{
32    fetch::Fetch,
33    query_data::{
34        BlockHash, BlockQueryData, LeafHash, LeafQueryData, PayloadMetadata, PayloadQueryData,
35        QueryableHeader, QueryablePayload, TransactionHash, VidCommonMetadata, VidCommonQueryData,
36    },
37    BlockWithTransaction,
38};
39use crate::{types::HeightIndexed, Header, Payload};
40
41#[derive(Derivative, From, Display)]
42#[derivative(Ord = "feature_allow_slow_enum")]
43#[derivative(
44    Copy(bound = ""),
45    Debug(bound = ""),
46    PartialEq(bound = ""),
47    Eq(bound = ""),
48    Ord(bound = ""),
49    Hash(bound = "")
50)]
51pub enum LeafId<Types: NodeType> {
52    #[display("{_0}")]
53    Number(usize),
54    #[display("{_0}")]
55    Hash(LeafHash<Types>),
56}
57
58impl<Types: NodeType> Clone for LeafId<Types> {
59    fn clone(&self) -> Self {
60        *self
61    }
62}
63
64impl<Types: NodeType> PartialOrd for LeafId<Types> {
65    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
66        Some(self.cmp(other))
67    }
68}
69
70#[derive(Derivative, From, Display)]
71#[derivative(Ord = "feature_allow_slow_enum")]
72#[derivative(
73    Copy(bound = ""),
74    Debug(bound = ""),
75    PartialEq(bound = ""),
76    Eq(bound = ""),
77    Ord(bound = ""),
78    Hash(bound = "")
79)]
80pub enum BlockId<Types: NodeType> {
81    #[display("{_0}")]
82    Number(usize),
83    #[display("{_0}")]
84    Hash(BlockHash<Types>),
85    #[display("{_0}")]
86    #[from(ignore)]
87    PayloadHash(VidCommitment),
88}
89
90impl<Types: NodeType> Clone for BlockId<Types> {
91    fn clone(&self) -> Self {
92        *self
93    }
94}
95
96impl<Types: NodeType> PartialOrd for BlockId<Types> {
97    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
98        Some(self.cmp(other))
99    }
100}
101
102pub type FetchStream<T> = BoxStream<'static, Fetch<T>>;
103
104/// An interface for querying a HotShot blockchain.
105///
106/// This interface provides expressive queries over all the data which is made available by HotShot
107/// consensus. The data exposed by this interface consists entirely of _normative_ data: data which
108/// every correct HotShot node or light client will agree on, and which is guaranteed by consensus
109/// to be immutable. This immutability has an interesting consequence: all of the methods exposed by
110/// this trait are _pure_: given equivalent inputs, the same method will always return equivalent
111/// outputs[^1].
112///
113/// This purity property has a further consequence: none of the methods defined here can fail! Even
114/// if you query for a block at a position past the end of the current chain -- a block which does
115/// not exist yet -- the query will not fail. It will return an in-progress [`Fetch`] which, when it
116/// finally does resolve, resolves to the unique block at that position in the chain. All subsequent
117/// queries for the same position will eventually resolve to the same block.
118///
119/// In other words, the abstraction is that of an infinitely long chain which exists statically, in
120/// its entirety, at all times. In reality, of course, this chain is being produced incrementally
121/// and has a finite length at any given time. But all this means is that some queries may take a
122/// long time to resolve while others may resolve immediately.
123///
124/// [^1]: The data returned by these methods are wrapped in [`Fetch`], which does not implement
125///       [`PartialEq]`. So to speak of equivalent outputs, we need to define an equivalence
126///       relation on [`Fetch<T>`]. The relation we will use is defined when `T: PartialEq`, and
127///       defines two fetches `f1` and `f2` as equivalent when `f1.await == f2.await`. That is,
128///       depending on when you call a certain method, you may or may not get a response
129///       immediately. But whenever you do get the data you requested, it is unique for that
130///       combination of inputs.
131#[async_trait]
132pub trait AvailabilityDataSource<Types: NodeType>
133where
134    Header<Types>: QueryableHeader<Types>,
135    Payload<Types>: QueryablePayload<Types>,
136{
137    async fn get_leaf<ID>(&self, id: ID) -> Fetch<LeafQueryData<Types>>
138    where
139        ID: Into<LeafId<Types>> + Send + Sync;
140
141    async fn get_header<ID>(&self, id: ID) -> Fetch<Header<Types>>
142    where
143        ID: Into<BlockId<Types>> + Send + Sync;
144
145    async fn get_block<ID>(&self, id: ID) -> Fetch<BlockQueryData<Types>>
146    where
147        ID: Into<BlockId<Types>> + Send + Sync;
148
149    async fn get_payload<ID>(&self, id: ID) -> Fetch<PayloadQueryData<Types>>
150    where
151        ID: Into<BlockId<Types>> + Send + Sync;
152
153    async fn get_payload_metadata<ID>(&self, id: ID) -> Fetch<PayloadMetadata<Types>>
154    where
155        ID: Into<BlockId<Types>> + Send + Sync;
156
157    async fn get_vid_common<ID>(&self, id: ID) -> Fetch<VidCommonQueryData<Types>>
158    where
159        ID: Into<BlockId<Types>> + Send + Sync;
160
161    async fn get_vid_common_metadata<ID>(&self, id: ID) -> Fetch<VidCommonMetadata<Types>>
162    where
163        ID: Into<BlockId<Types>> + Send + Sync;
164
165    async fn get_leaf_range<R>(&self, range: R) -> FetchStream<LeafQueryData<Types>>
166    where
167        R: RangeBounds<usize> + Send + 'static;
168
169    async fn get_header_range<R>(&self, range: R) -> FetchStream<Header<Types>>
170    where
171        R: RangeBounds<usize> + Send + 'static;
172
173    async fn get_block_range<R>(&self, range: R) -> FetchStream<BlockQueryData<Types>>
174    where
175        R: RangeBounds<usize> + Send + 'static;
176
177    async fn get_payload_range<R>(&self, range: R) -> FetchStream<PayloadQueryData<Types>>
178    where
179        R: RangeBounds<usize> + Send + 'static;
180
181    async fn get_payload_metadata_range<R>(&self, range: R) -> FetchStream<PayloadMetadata<Types>>
182    where
183        R: RangeBounds<usize> + Send + 'static;
184
185    async fn get_vid_common_range<R>(&self, range: R) -> FetchStream<VidCommonQueryData<Types>>
186    where
187        R: RangeBounds<usize> + Send + 'static;
188
189    async fn get_vid_common_metadata_range<R>(
190        &self,
191        range: R,
192    ) -> FetchStream<VidCommonMetadata<Types>>
193    where
194        R: RangeBounds<usize> + Send + 'static;
195
196    async fn get_leaf_range_rev(
197        &self,
198        start: Bound<usize>,
199        end: usize,
200    ) -> FetchStream<LeafQueryData<Types>>;
201
202    async fn get_block_range_rev(
203        &self,
204        start: Bound<usize>,
205        end: usize,
206    ) -> FetchStream<BlockQueryData<Types>>;
207
208    async fn get_payload_range_rev(
209        &self,
210        start: Bound<usize>,
211        end: usize,
212    ) -> FetchStream<PayloadQueryData<Types>>;
213
214    async fn get_payload_metadata_range_rev(
215        &self,
216        start: Bound<usize>,
217        end: usize,
218    ) -> FetchStream<PayloadMetadata<Types>>;
219
220    async fn get_vid_common_range_rev(
221        &self,
222        start: Bound<usize>,
223        end: usize,
224    ) -> FetchStream<VidCommonQueryData<Types>>;
225
226    async fn get_vid_common_metadata_range_rev(
227        &self,
228        start: Bound<usize>,
229        end: usize,
230    ) -> FetchStream<VidCommonMetadata<Types>>;
231
232    async fn get_block_containing_transaction(
233        &self,
234        h: TransactionHash<Types>,
235    ) -> Fetch<BlockWithTransaction<Types>>;
236
237    async fn subscribe_blocks(&self, from: usize) -> BoxStream<'static, BlockQueryData<Types>> {
238        self.get_block_range(from..)
239            .await
240            .then(Fetch::resolve)
241            .boxed()
242    }
243
244    async fn subscribe_payloads(&self, from: usize) -> BoxStream<'static, PayloadQueryData<Types>> {
245        self.get_payload_range(from..)
246            .await
247            .then(Fetch::resolve)
248            .boxed()
249    }
250
251    async fn subscribe_payload_metadata(
252        &self,
253        from: usize,
254    ) -> BoxStream<'static, PayloadMetadata<Types>> {
255        self.get_payload_metadata_range(from..)
256            .await
257            .then(Fetch::resolve)
258            .boxed()
259    }
260
261    async fn subscribe_leaves(&self, from: usize) -> BoxStream<'static, LeafQueryData<Types>> {
262        self.get_leaf_range(from..)
263            .await
264            .then(Fetch::resolve)
265            .boxed()
266    }
267
268    async fn subscribe_headers(&self, from: usize) -> BoxStream<'static, Header<Types>> {
269        self.get_header_range(from..)
270            .await
271            .then(Fetch::resolve)
272            .boxed()
273    }
274
275    async fn subscribe_vid_common(
276        &self,
277        from: usize,
278    ) -> BoxStream<'static, VidCommonQueryData<Types>> {
279        self.get_vid_common_range(from..)
280            .await
281            .then(Fetch::resolve)
282            .boxed()
283    }
284
285    async fn subscribe_vid_common_metadata(
286        &self,
287        from: usize,
288    ) -> BoxStream<'static, VidCommonMetadata<Types>> {
289        self.get_vid_common_metadata_range(from..)
290            .await
291            .then(Fetch::resolve)
292            .boxed()
293    }
294}
295
296/// Information about a block.
297///
298/// This type encapsulate all the information we might have about a decided HotShot block:
299/// * The leaf, including a header and consensus metadata
300/// * The block itself, which may be missing if this node did not receive a DA proposal for this
301///   block
302/// * VID common and a unique VID share, which may be missing if this node did not receive a VID
303///   share for this block
304#[derive(Clone, Debug)]
305pub struct BlockInfo<Types: NodeType> {
306    pub leaf: LeafQueryData<Types>,
307    pub block: Option<BlockQueryData<Types>>,
308    pub vid_common: Option<VidCommonQueryData<Types>>,
309    pub vid_share: Option<VidShare>,
310    pub qc_chain: Option<[CertificatePair<Types>; 2]>,
311}
312
313impl<Types: NodeType> From<LeafQueryData<Types>> for BlockInfo<Types> {
314    fn from(leaf: LeafQueryData<Types>) -> Self {
315        Self::new(leaf, None, None, None)
316    }
317}
318
319impl<Types: NodeType> HeightIndexed for BlockInfo<Types> {
320    fn height(&self) -> u64 {
321        self.leaf.height()
322    }
323}
324
325impl<Types: NodeType> BlockInfo<Types> {
326    pub fn new(
327        leaf: LeafQueryData<Types>,
328        block: Option<BlockQueryData<Types>>,
329        vid_common: Option<VidCommonQueryData<Types>>,
330        vid_share: Option<VidShare>,
331    ) -> Self {
332        Self {
333            leaf,
334            block,
335            vid_common,
336            vid_share,
337            qc_chain: None,
338        }
339    }
340
341    pub fn with_qc_chain(mut self, qc_chain: [CertificatePair<Types>; 2]) -> Self {
342        self.qc_chain = Some(qc_chain);
343        self
344    }
345}
346
347pub trait UpdateAvailabilityData<Types: NodeType> {
348    /// Append information about a new block to the database.
349    fn append(&self, info: BlockInfo<Types>) -> impl Send + Future<Output = anyhow::Result<()>>;
350}