hotshot_query_service/fetching/
request.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//! Requests for fetching resources.
14
15use std::{fmt::Debug, hash::Hash};
16
17use alloy::primitives::{FixedBytes, Keccak256};
18use derive_more::{From, Into};
19use hotshot_types::{
20    data::{VidCommitment, VidCommon},
21    traits::node_implementation::NodeType,
22};
23
24use crate::{
25    Payload,
26    availability::{
27        BlockQueryData, LeafHash, LeafQueryData, QcHash, QueryableHeader, VidCommonQueryData,
28    },
29    fetching::NonEmptyRange,
30};
31
32/// A request for a resource.
33pub trait Request<Types>: Copy + Debug + Eq + Hash + Send {
34    /// The type of resource that will be returned as a successful response to this request.
35    type Response: Clone + Send;
36}
37
38/// A request for a payload with a given commitment.
39#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
40pub struct PayloadRequest(pub VidCommitment);
41
42impl<Types: NodeType> Request<Types> for PayloadRequest {
43    type Response = Payload<Types>;
44}
45
46/// A request for a consecutive range of objects.
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
48pub struct RangeRequest {
49    /// The first block in the requested range.
50    pub start: u64,
51
52    /// The first block after the requested range.
53    pub end: u64,
54
55    /// The Keccak256 hash of the concatenation of the expected payload commitments.
56    ///
57    /// This can be used to verify the fetched data. We use the hash rather than passing in the full
58    /// list of expected payload commitments because a [`Request`] is expected to be small and easy
59    /// to copy and pass around.
60    pub expected_hash: FixedBytes<32>,
61}
62
63impl RangeRequest {
64    /// A request for a range of data corresponding to a range of headers.
65    pub fn from_headers<Types: NodeType>(
66        headers: &NonEmptyRange<impl QueryableHeader<Types>>,
67    ) -> Self {
68        let expected_hash =
69            Self::hash_payloads(headers.iter().map(|header| header.payload_commitment()));
70        Self {
71            start: headers.start(),
72            end: headers.end(),
73            expected_hash,
74        }
75    }
76
77    /// Compute the expected hash of a range of payload commitments.
78    pub fn hash_payloads(
79        payload_commitments: impl IntoIterator<Item = VidCommitment>,
80    ) -> FixedBytes<32> {
81        let mut hasher = Keccak256::new();
82        for comm in payload_commitments {
83            hasher.update(comm);
84        }
85        hasher.finalize()
86    }
87}
88
89/// A request for a consecutive range of blocks.
90#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, From, Into)]
91pub struct BlockRangeRequest(RangeRequest);
92
93impl<Types: NodeType> Request<Types> for BlockRangeRequest {
94    type Response = NonEmptyRange<BlockQueryData<Types>>;
95}
96
97impl BlockRangeRequest {
98    pub fn from_headers<Types: NodeType>(
99        headers: &NonEmptyRange<impl QueryableHeader<Types>>,
100    ) -> Self {
101        RangeRequest::from_headers(headers).into()
102    }
103}
104
105/// A request for VID common data.
106#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
107pub struct VidCommonRequest(pub VidCommitment);
108
109impl<Types: NodeType> Request<Types> for VidCommonRequest {
110    type Response = VidCommon;
111}
112
113/// A request for a consecutive range of VID common.
114#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, From, Into)]
115pub struct VidCommonRangeRequest(RangeRequest);
116
117impl<Types: NodeType> Request<Types> for VidCommonRangeRequest {
118    type Response = NonEmptyRange<VidCommonQueryData<Types>>;
119}
120
121impl VidCommonRangeRequest {
122    pub fn from_headers<Types: NodeType>(
123        headers: &NonEmptyRange<impl QueryableHeader<Types>>,
124    ) -> Self {
125        RangeRequest::from_headers(headers).into()
126    }
127}
128
129/// A request for a leaf with a given height.
130///
131/// The expected hash and QC hash are also provided, so that the request can be verified against a
132/// response from an untrusted provider.
133#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, From, Into)]
134pub struct LeafRequest<Types: NodeType> {
135    pub height: u64,
136    pub expected_leaf: LeafHash<Types>,
137    pub expected_qc: QcHash<Types>,
138}
139
140impl<Types: NodeType> LeafRequest<Types> {
141    pub fn new(height: u64, expected_leaf: LeafHash<Types>, expected_qc: QcHash<Types>) -> Self {
142        Self {
143            height,
144            expected_leaf,
145            expected_qc,
146        }
147    }
148}
149
150impl<Types: NodeType> Request<Types> for LeafRequest<Types> {
151    type Response = LeafQueryData<Types>;
152}
153
154/// A request for a consecutive range of VID common.
155#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
156pub struct LeafRangeRequest<Types: NodeType> {
157    /// The first block in the requested range.
158    pub start: u64,
159
160    /// The first block after the requested range.
161    pub end: u64,
162
163    /// The expected hash of the last leaf in the chain.
164    ///
165    /// Earlier leaves can be verified based on the subsequent leaf.
166    pub last_leaf: LeafHash<Types>,
167
168    /// The expected hash of the last QC in the chain.
169    ///
170    /// Earlier QCs can be verified based on the subsequent leaf.
171    pub last_qc: QcHash<Types>,
172}
173
174impl<Types: NodeType> Request<Types> for LeafRangeRequest<Types> {
175    type Response = NonEmptyRange<LeafQueryData<Types>>;
176}