1use std::{collections::HashMap, time::Duration};
2
3use alloy::primitives::Address;
4use anyhow::Context;
5use async_trait::async_trait;
6use committable::Commitment;
7use espresso_types::{
8 config::PublicNetworkConfig,
9 v0::traits::{PersistenceOptions, SequencerPersistence},
10 v0_3::{
11 ChainConfig, RewardAccountProofV1, RewardAccountQueryDataV1, RewardAccountV1, RewardAmount,
12 RewardMerkleTreeV1, Validator,
13 },
14 v0_4::{RewardAccountProofV2, RewardAccountQueryDataV2, RewardAccountV2, RewardMerkleTreeV2},
15 FeeAccount, FeeAccountProof, FeeMerkleTree, Leaf2, NodeState, PubKey, Transaction,
16};
17use futures::future::Future;
18use hotshot::types::BLSPubKey;
19use hotshot_query_service::{
20 availability::{AvailabilityDataSource, VidCommonQueryData},
21 data_source::{UpdateDataSource, VersionedDataSource},
22 fetching::provider::{AnyProvider, QueryServiceProvider},
23 node::NodeDataSource,
24 status::StatusDataSource,
25};
26use hotshot_types::{
27 data::{EpochNumber, VidShare, ViewNumber},
28 light_client::LCV3StateSignatureRequestBody,
29 traits::{
30 network::ConnectedNetwork,
31 node_implementation::{NodeType, Versions},
32 },
33 PeerConfig,
34};
35use indexmap::IndexMap;
36use serde::{Deserialize, Serialize};
37use tide_disco::Url;
38
39use super::{
40 fs,
41 options::{Options, Query},
42 sql, AccountQueryData, BlocksFrontier,
43};
44use crate::{persistence, SeqTypes, SequencerApiVersion};
45
46pub trait DataSourceOptions: PersistenceOptions {
47 type DataSource: SequencerDataSource<Options = Self>;
48
49 fn enable_query_module(&self, opt: Options, query: Query) -> Options;
50}
51
52impl DataSourceOptions for persistence::sql::Options {
53 type DataSource = sql::DataSource;
54
55 fn enable_query_module(&self, opt: Options, query: Query) -> Options {
56 opt.query_sql(query, self.clone())
57 }
58}
59
60impl DataSourceOptions for persistence::fs::Options {
61 type DataSource = fs::DataSource;
62
63 fn enable_query_module(&self, opt: Options, query: Query) -> Options {
64 opt.query_fs(query, self.clone())
65 }
66}
67
68#[async_trait]
73pub trait SequencerDataSource:
74 AvailabilityDataSource<SeqTypes>
75 + NodeDataSource<SeqTypes>
76 + StatusDataSource
77 + UpdateDataSource<SeqTypes>
78 + VersionedDataSource
79 + Sized
80{
81 type Options: DataSourceOptions<DataSource = Self>;
82
83 async fn create(opt: Self::Options, provider: Provider, reset: bool) -> anyhow::Result<Self>;
85}
86
87pub type Provider = AnyProvider<SeqTypes>;
89
90pub fn provider<V: Versions>(
92 peers: impl IntoIterator<Item = Url>,
93 bind_version: SequencerApiVersion,
94) -> Provider {
95 let mut provider = Provider::default();
96 for peer in peers {
97 tracing::info!("will fetch missing data from {peer}");
98 provider = provider.with_provider(QueryServiceProvider::new(peer, bind_version));
99 }
100 provider
101}
102
103pub(crate) trait SubmitDataSource<N: ConnectedNetwork<PubKey>, P: SequencerPersistence> {
104 fn submit(&self, tx: Transaction) -> impl Send + Future<Output = anyhow::Result<()>>;
105}
106
107pub(crate) trait HotShotConfigDataSource {
108 fn get_config(&self) -> impl Send + Future<Output = PublicNetworkConfig>;
109}
110
111#[async_trait]
112pub(crate) trait StateSignatureDataSource<N: ConnectedNetwork<PubKey>> {
113 async fn get_state_signature(&self, height: u64) -> Option<LCV3StateSignatureRequestBody>;
114}
115
116pub(crate) trait NodeStateDataSource {
117 fn node_state(&self) -> impl Send + Future<Output = NodeState>;
118}
119
120#[derive(Serialize, Deserialize)]
121#[serde(bound = "T: NodeType")]
122pub struct StakeTableWithEpochNumber<T: NodeType> {
123 pub epoch: Option<EpochNumber>,
124 pub stake_table: Vec<PeerConfig<T>>,
125}
126
127pub(crate) trait StakeTableDataSource<T: NodeType> {
128 fn get_stake_table(
130 &self,
131 epoch: Option<<T as NodeType>::Epoch>,
132 ) -> impl Send + Future<Output = anyhow::Result<Vec<PeerConfig<T>>>>;
133
134 fn get_stake_table_current(
136 &self,
137 ) -> impl Send + Future<Output = anyhow::Result<StakeTableWithEpochNumber<T>>>;
138
139 fn get_validators(
141 &self,
142 epoch: <T as NodeType>::Epoch,
143 ) -> impl Send + Future<Output = anyhow::Result<IndexMap<Address, Validator<BLSPubKey>>>>;
144
145 fn get_block_reward(
146 &self,
147 epoch: Option<EpochNumber>,
148 ) -> impl Send + Future<Output = anyhow::Result<Option<RewardAmount>>>;
149 fn current_proposal_participation(
151 &self,
152 ) -> impl Send + Future<Output = HashMap<BLSPubKey, f64>>;
153
154 fn previous_proposal_participation(
156 &self,
157 ) -> impl Send + Future<Output = HashMap<BLSPubKey, f64>>;
158}
159
160pub(crate) trait CatchupDataSource: Sync {
161 fn get_account(
168 &self,
169 instance: &NodeState,
170 height: u64,
171 view: ViewNumber,
172 account: FeeAccount,
173 ) -> impl Send + Future<Output = anyhow::Result<AccountQueryData>> {
174 async move {
175 let tree = self
176 .get_accounts(instance, height, view, &[account])
177 .await?;
178 let (proof, balance) = FeeAccountProof::prove(&tree, account.into()).context(
179 format!("account {account} not available for height {height}, view {view}"),
180 )?;
181 Ok(AccountQueryData { balance, proof })
182 }
183 }
184
185 fn get_accounts(
192 &self,
193 instance: &NodeState,
194 height: u64,
195 view: ViewNumber,
196 accounts: &[FeeAccount],
197 ) -> impl Send + Future<Output = anyhow::Result<FeeMerkleTree>>;
198
199 fn get_frontier(
206 &self,
207 instance: &NodeState,
208 height: u64,
209 view: ViewNumber,
210 ) -> impl Send + Future<Output = anyhow::Result<BlocksFrontier>>;
211
212 fn get_chain_config(
213 &self,
214 commitment: Commitment<ChainConfig>,
215 ) -> impl Send + Future<Output = anyhow::Result<ChainConfig>>;
216
217 fn get_leaf_chain(
218 &self,
219 height: u64,
220 ) -> impl Send + Future<Output = anyhow::Result<Vec<Leaf2>>>;
221
222 fn get_reward_account_v2(
229 &self,
230 instance: &NodeState,
231 height: u64,
232 view: ViewNumber,
233 account: RewardAccountV2,
234 ) -> impl Send + Future<Output = anyhow::Result<RewardAccountQueryDataV2>> {
235 async move {
236 let tree = self
237 .get_reward_accounts_v2(instance, height, view, &[account])
238 .await?;
239 let (proof, balance) = RewardAccountProofV2::prove(&tree, account.into()).context(
240 format!("reward account {account} not available for height {height}, view {view}"),
241 )?;
242 Ok(RewardAccountQueryDataV2 { balance, proof })
243 }
244 }
245
246 fn get_reward_accounts_v2(
247 &self,
248 instance: &NodeState,
249 height: u64,
250 view: ViewNumber,
251 accounts: &[RewardAccountV2],
252 ) -> impl Send + Future<Output = anyhow::Result<RewardMerkleTreeV2>>;
253
254 fn get_reward_account_v1(
255 &self,
256 instance: &NodeState,
257 height: u64,
258 view: ViewNumber,
259 account: RewardAccountV1,
260 ) -> impl Send + Future<Output = anyhow::Result<RewardAccountQueryDataV1>> {
261 async move {
262 let tree = self
263 .get_reward_accounts_v1(instance, height, view, &[account])
264 .await?;
265 let (proof, balance) = RewardAccountProofV1::prove(&tree, account.into()).context(
266 format!("reward account {account} not available for height {height}, view {view}"),
267 )?;
268 Ok(RewardAccountQueryDataV1 { balance, proof })
269 }
270 }
271
272 fn get_reward_accounts_v1(
273 &self,
274 instance: &NodeState,
275 height: u64,
276 view: ViewNumber,
277 accounts: &[RewardAccountV1],
278 ) -> impl Send + Future<Output = anyhow::Result<RewardMerkleTreeV1>>;
279}
280
281#[async_trait]
282pub trait RequestResponseDataSource<Types: NodeType> {
283 async fn request_vid_shares(
284 &self,
285 block_number: u64,
286 vid_common_data: VidCommonQueryData<Types>,
287 duration: Duration,
288 ) -> anyhow::Result<Vec<VidShare>>;
289}
290
291#[cfg(any(test, feature = "testing"))]
292pub mod testing {
293 use super::{super::Options, *};
294
295 #[async_trait]
296 pub trait TestableSequencerDataSource: SequencerDataSource {
297 type Storage: Sync;
298
299 async fn create_storage() -> Self::Storage;
300 fn persistence_options(storage: &Self::Storage) -> Self::Options;
301 fn leaf_only_ds_options(
302 _storage: &Self::Storage,
303 _opt: Options,
304 ) -> anyhow::Result<Options> {
305 anyhow::bail!("not supported")
306 }
307 fn options(storage: &Self::Storage, opt: Options) -> Options;
308 }
309}