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