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 FeeAccount, FeeAccountProof, FeeMerkleTree, Leaf2, NodeState, PubKey, Transaction,
9 config::PublicNetworkConfig,
10 v0::traits::{PersistenceOptions, SequencerPersistence},
11 v0_3::{
12 AuthenticatedValidator, ChainConfig, RegisteredValidator, RewardAccountProofV1,
13 RewardAccountQueryDataV1, RewardAccountV1, RewardAmount, RewardMerkleTreeV1,
14 StakeTableEvent,
15 },
16 v0_4::{RewardAccountProofV2, RewardAccountQueryDataV2, RewardAccountV2, RewardMerkleTreeV2},
17};
18use futures::future::{BoxFuture, Future};
19use hotshot::types::BLSPubKey;
20use hotshot_query_service::{
21 availability::{AvailabilityDataSource, VidCommonQueryData},
22 data_source::{UpdateDataSource, VersionedDataSource},
23 fetching::provider::{AnyProvider, QueryServiceProvider},
24 node::NodeDataSource,
25 status::StatusDataSource,
26};
27use hotshot_types::{
28 PeerConfig,
29 data::{EpochNumber, VidShare, ViewNumber},
30 light_client::LCV3StateSignatureRequestBody,
31 simple_certificate::LightClientStateUpdateCertificateV2,
32 traits::{network::ConnectedNetwork, node_implementation::NodeType},
33};
34use indexmap::IndexMap;
35use serde::{Deserialize, Serialize};
36use tide_disco::Url;
37
38use super::{
39 AccountQueryData, BlocksFrontier, fs,
40 options::{Options, Query},
41 sql,
42};
43use crate::{SeqTypes, SequencerApiVersion, U256, persistence, state_cert::StateCertFetchError};
44
45pub trait DataSourceOptions: PersistenceOptions {
46 type DataSource: SequencerDataSource<Options = Self>;
47
48 fn enable_query_module(&self, opt: Options, query: Query) -> Options;
49}
50
51impl DataSourceOptions for persistence::sql::Options {
52 type DataSource = sql::DataSource;
53
54 fn enable_query_module(&self, opt: Options, query: Query) -> Options {
55 opt.query_sql(query, self.clone())
56 }
57}
58
59impl DataSourceOptions for persistence::fs::Options {
60 type DataSource = fs::DataSource;
61
62 fn enable_query_module(&self, opt: Options, query: Query) -> Options {
63 opt.query_fs(query, self.clone())
64 }
65}
66
67#[async_trait]
72pub trait SequencerDataSource:
73 AvailabilityDataSource<SeqTypes>
74 + NodeDataSource<SeqTypes>
75 + StatusDataSource
76 + UpdateDataSource<SeqTypes>
77 + VersionedDataSource
78 + Sized
79{
80 type Options: DataSourceOptions<DataSource = Self>;
81
82 async fn create(opt: Self::Options, provider: Provider, reset: bool) -> anyhow::Result<Self>;
84}
85
86pub type Provider = AnyProvider<SeqTypes>;
88
89pub fn provider(
91 peers: impl IntoIterator<Item = Url>,
92 bind_version: SequencerApiVersion,
93) -> Provider {
94 let mut provider = Provider::default();
95 for peer in peers {
96 tracing::info!("will fetch missing data from {peer}");
97 provider = provider.with_provider(QueryServiceProvider::new(peer, bind_version));
98 }
99 provider
100}
101
102pub(crate) trait SubmitDataSource<N: ConnectedNetwork<PubKey>, P: SequencerPersistence> {
103 fn submit(&self, tx: Transaction) -> impl Send + Future<Output = anyhow::Result<()>>;
104}
105
106pub(crate) trait HotShotConfigDataSource {
107 fn get_config(&self) -> impl Send + Future<Output = PublicNetworkConfig>;
108}
109
110#[async_trait]
111pub(crate) trait StateSignatureDataSource<N: ConnectedNetwork<PubKey>> {
112 async fn get_state_signature(&self, height: u64) -> Option<LCV3StateSignatureRequestBody>;
113}
114
115pub(crate) trait NodeStateDataSource {
116 fn node_state(&self) -> impl Send + Future<Output = NodeState>;
117}
118
119pub(crate) trait TokenDataSource<T: NodeType> {
120 fn get_initial_supply_l1(&self) -> impl Send + Future<Output = anyhow::Result<U256>>;
121 fn get_total_supply_l1(&self) -> impl Send + Future<Output = anyhow::Result<U256>>;
122 fn get_decided_header(&self) -> impl Send + Future<Output = espresso_types::Header>;
123}
124
125#[derive(Serialize, Deserialize)]
126#[serde(bound = "T: NodeType")]
127pub struct StakeTableWithEpochNumber<T: NodeType> {
128 pub epoch: Option<EpochNumber>,
129 pub stake_table: Vec<PeerConfig<T>>,
130}
131
132pub(crate) trait StakeTableDataSource<T: NodeType> {
133 fn get_stake_table(
135 &self,
136 epoch: Option<EpochNumber>,
137 ) -> impl Send + Future<Output = anyhow::Result<Vec<PeerConfig<T>>>>;
138
139 fn get_stake_table_current(
141 &self,
142 ) -> impl Send + Future<Output = anyhow::Result<StakeTableWithEpochNumber<T>>>;
143
144 fn get_da_stake_table(
146 &self,
147 epoch: Option<EpochNumber>,
148 ) -> impl Send + Future<Output = anyhow::Result<Vec<PeerConfig<T>>>>;
149
150 fn get_da_stake_table_current(
152 &self,
153 ) -> impl Send + Future<Output = anyhow::Result<StakeTableWithEpochNumber<T>>>;
154
155 fn get_validators(
157 &self,
158 epoch: EpochNumber,
159 ) -> impl Send + Future<Output = anyhow::Result<IndexMap<Address, AuthenticatedValidator<BLSPubKey>>>>;
160
161 fn get_block_reward(
162 &self,
163 epoch: Option<EpochNumber>,
164 ) -> impl Send + Future<Output = anyhow::Result<Option<RewardAmount>>>;
165 fn current_proposal_participation(
167 &self,
168 ) -> impl Send + Future<Output = HashMap<BLSPubKey, f64>>;
169
170 fn proposal_participation(
172 &self,
173 epoch: EpochNumber,
174 ) -> impl Send + Future<Output = HashMap<BLSPubKey, f64>>;
175 fn current_vote_participation(&self) -> impl Send + Future<Output = HashMap<BLSPubKey, f64>>;
177
178 fn vote_participation(
180 &self,
181 epoch: EpochNumber,
182 ) -> impl Send + Future<Output = HashMap<BLSPubKey, f64>>;
183
184 fn get_all_validators(
185 &self,
186 epoch: EpochNumber,
187 offset: u64,
188 limit: u64,
189 ) -> impl Send + Future<Output = anyhow::Result<Vec<RegisteredValidator<PubKey>>>>;
190
191 fn stake_table_events(
193 &self,
194 from_l1_block: u64,
195 to_l1_block: u64,
196 ) -> impl Send + Future<Output = anyhow::Result<Vec<StakeTableEvent>>>;
197}
198
199#[async_trait]
201pub(crate) trait StateCertDataSource {
202 async fn get_state_cert_by_epoch(
203 &self,
204 epoch: u64,
205 ) -> anyhow::Result<Option<LightClientStateUpdateCertificateV2<SeqTypes>>>;
206
207 async fn insert_state_cert(
208 &self,
209 epoch: u64,
210 cert: LightClientStateUpdateCertificateV2<SeqTypes>,
211 ) -> anyhow::Result<()>;
212}
213
214pub(crate) trait CatchupDataSource: Sync {
215 fn get_account(
222 &self,
223 instance: &NodeState,
224 height: u64,
225 view: ViewNumber,
226 account: FeeAccount,
227 ) -> impl Send + Future<Output = anyhow::Result<AccountQueryData>> {
228 async move {
229 let tree = self
230 .get_accounts(instance, height, view, &[account])
231 .await?;
232 let (proof, balance) = FeeAccountProof::prove(&tree, account.into()).context(
233 format!("account {account} not available for height {height}, view {view}"),
234 )?;
235 Ok(AccountQueryData { balance, proof })
236 }
237 }
238
239 fn get_accounts(
246 &self,
247 instance: &NodeState,
248 height: u64,
249 view: ViewNumber,
250 accounts: &[FeeAccount],
251 ) -> impl Send + Future<Output = anyhow::Result<FeeMerkleTree>>;
252
253 fn get_frontier(
260 &self,
261 instance: &NodeState,
262 height: u64,
263 view: ViewNumber,
264 ) -> impl Send + Future<Output = anyhow::Result<BlocksFrontier>>;
265
266 fn get_chain_config(
267 &self,
268 commitment: Commitment<ChainConfig>,
269 ) -> impl Send + Future<Output = anyhow::Result<ChainConfig>>;
270
271 fn get_leaf_chain(
272 &self,
273 height: u64,
274 ) -> impl Send + Future<Output = anyhow::Result<Vec<Leaf2>>>;
275
276 fn get_reward_account_v2(
283 &self,
284 instance: &NodeState,
285 height: u64,
286 view: ViewNumber,
287 account: RewardAccountV2,
288 ) -> impl Send + Future<Output = anyhow::Result<RewardAccountQueryDataV2>> {
289 async move {
290 let tree = self
291 .get_reward_accounts_v2(instance, height, view, &[account])
292 .await?;
293 let (proof, balance) = RewardAccountProofV2::prove(&tree, account.into()).context(
294 format!("reward account {account} not available for height {height}, view {view}"),
295 )?;
296 Ok(RewardAccountQueryDataV2 { balance, proof })
297 }
298 }
299
300 fn get_reward_accounts_v2(
301 &self,
302 instance: &NodeState,
303 height: u64,
304 view: ViewNumber,
305 accounts: &[RewardAccountV2],
306 ) -> impl Send + Future<Output = anyhow::Result<RewardMerkleTreeV2>>;
307
308 fn get_reward_account_v1(
309 &self,
310 instance: &NodeState,
311 height: u64,
312 view: ViewNumber,
313 account: RewardAccountV1,
314 ) -> impl Send + Future<Output = anyhow::Result<RewardAccountQueryDataV1>> {
315 async move {
316 let tree = self
317 .get_reward_accounts_v1(instance, height, view, &[account])
318 .await?;
319 let (proof, balance) = RewardAccountProofV1::prove(&tree, account.into()).context(
320 format!("reward account {account} not available for height {height}, view {view}"),
321 )?;
322 Ok(RewardAccountQueryDataV1 { balance, proof })
323 }
324 }
325
326 fn get_reward_accounts_v1(
327 &self,
328 instance: &NodeState,
329 height: u64,
330 view: ViewNumber,
331 accounts: &[RewardAccountV1],
332 ) -> impl Send + Future<Output = anyhow::Result<RewardMerkleTreeV1>>;
333
334 fn get_reward_merkle_tree_v2(
335 &self,
336 height: u64,
337 view: ViewNumber,
338 ) -> impl Send + Future<Output = anyhow::Result<Vec<u8>>>;
339
340 fn get_state_cert(
341 &self,
342 epoch: u64,
343 ) -> impl Send + Future<Output = anyhow::Result<LightClientStateUpdateCertificateV2<SeqTypes>>>;
344}
345
346pub trait RequestResponseDataSource<Types: NodeType> {
347 fn request_vid_shares(
348 &self,
349 block_number: u64,
350 vid_common_data: VidCommonQueryData<Types>,
351 duration: Duration,
352 ) -> impl Future<Output = BoxFuture<'static, anyhow::Result<Vec<VidShare>>>> + Send;
353}
354
355#[async_trait]
356pub trait StateCertFetchingDataSource<Types: NodeType> {
357 async fn request_state_cert(
358 &self,
359 epoch: u64,
360 timeout: Duration,
361 ) -> Result<LightClientStateUpdateCertificateV2<Types>, StateCertFetchError>;
362}
363
364#[derive(Serialize, Deserialize, Clone, Debug)]
366pub struct TableSize {
367 pub table_name: String,
368 pub row_count: i64,
369 pub total_size_bytes: Option<i64>,
370}
371
372pub(crate) trait DatabaseMetadataSource {
376 fn get_table_sizes(&self) -> impl Send + Future<Output = anyhow::Result<Vec<TableSize>>>;
378}
379
380#[cfg(any(test, feature = "testing"))]
381pub mod testing {
382 use super::{super::Options, *};
383
384 #[async_trait]
385 pub trait TestableSequencerDataSource: SequencerDataSource {
386 type Storage: Sync;
387
388 async fn create_storage() -> Self::Storage;
389 fn persistence_options(storage: &Self::Storage) -> Self::Options;
390 fn leaf_only_ds_options(
391 _storage: &Self::Storage,
392 _opt: Options,
393 ) -> anyhow::Result<Options> {
394 anyhow::bail!("not supported")
395 }
396 fn options(storage: &Self::Storage, opt: Options) -> Options;
397 }
398}