1use std::{
14 ops::{Bound, RangeBounds},
15 sync::Arc,
16};
17
18use async_trait::async_trait;
19use futures::stream::BoxStream;
20use hotshot::types::Event;
21use hotshot_events_service::events_source::{EventFilterSet, EventsSource, StartupInfo};
22use hotshot_types::{data::VidShare, event::LegacyEvent, traits::node_implementation::NodeType};
23use jf_merkle_tree_compat::prelude::MerkleProof;
24use tagged_base64::TaggedBase64;
25
26use super::VersionedDataSource;
27use crate::{
28 Header, Payload, QueryResult, Transaction,
29 availability::{
30 AvailabilityDataSource, BlockId, BlockInfo, BlockQueryData, BlockWithTransaction,
31 Certificate2, Fetch, FetchStream, LeafId, LeafQueryData, NamespaceId, PayloadMetadata,
32 PayloadQueryData, QueryableHeader, QueryablePayload, TransactionHash,
33 UpdateAvailabilityData, VidCommonMetadata, VidCommonQueryData,
34 },
35 data_source::storage::pruning::PrunedHeightDataSource,
36 explorer::{self, ExplorerDataSource, ExplorerHeader, ExplorerTransaction},
37 merklized_state::{
38 MerklizedState, MerklizedStateDataSource, MerklizedStateHeightPersistence, Snapshot,
39 UpdateStateData,
40 },
41 metrics::PrometheusMetrics,
42 node::{NodeDataSource, SyncStatusQueryData, TimeWindowQueryData, WindowStart},
43 status::{HasMetrics, StatusDataSource},
44};
45#[derive(Clone, Copy, Debug)]
82pub struct ExtensibleDataSource<D, U> {
83 data_source: D,
84 user_data: U,
85}
86
87impl<D, U> ExtensibleDataSource<D, U> {
88 pub fn new(data_source: D, user_data: U) -> Self {
89 Self {
90 data_source,
91 user_data,
92 }
93 }
94
95 pub fn inner(&self) -> &D {
101 &self.data_source
102 }
103
104 pub fn inner_mut(&mut self) -> &mut D {
110 &mut self.data_source
111 }
112}
113
114impl<D, U> AsRef<U> for ExtensibleDataSource<D, U> {
115 fn as_ref(&self) -> &U {
116 &self.user_data
117 }
118}
119
120impl<D, U> AsMut<U> for ExtensibleDataSource<D, U> {
121 fn as_mut(&mut self) -> &mut U {
122 &mut self.user_data
123 }
124}
125
126impl<D, U> VersionedDataSource for ExtensibleDataSource<D, U>
127where
128 D: VersionedDataSource + Send,
129 U: Send + Sync,
130{
131 type Transaction<'a>
132 = D::Transaction<'a>
133 where
134 Self: 'a;
135
136 type ReadOnly<'a>
137 = D::ReadOnly<'a>
138 where
139 Self: 'a;
140
141 async fn write(&self) -> anyhow::Result<Self::Transaction<'_>> {
142 self.data_source.write().await
143 }
144
145 async fn read(&self) -> anyhow::Result<Self::ReadOnly<'_>> {
146 self.data_source.read().await
147 }
148}
149
150#[async_trait]
151impl<D, U> PrunedHeightDataSource for ExtensibleDataSource<D, U>
152where
153 D: PrunedHeightDataSource + Send + Sync,
154 U: Send + Sync,
155{
156 async fn load_pruned_height(&self) -> anyhow::Result<Option<u64>> {
157 self.data_source.load_pruned_height().await
158 }
159
160 async fn load_state_pruned_height(&self) -> anyhow::Result<Option<u64>> {
161 self.data_source.load_state_pruned_height().await
162 }
163}
164
165#[async_trait]
166impl<D, U, Types> AvailabilityDataSource<Types> for ExtensibleDataSource<D, U>
167where
168 D: AvailabilityDataSource<Types> + Send + Sync,
169 U: Send + Sync,
170 Types: NodeType,
171 Header<Types>: QueryableHeader<Types>,
172 Payload<Types>: QueryablePayload<Types>,
173{
174 async fn get_leaf<ID>(&self, id: ID) -> Fetch<LeafQueryData<Types>>
175 where
176 ID: Into<LeafId<Types>> + Send + Sync,
177 {
178 self.data_source.get_leaf(id).await
179 }
180
181 async fn get_header<ID>(&self, id: ID) -> Fetch<Header<Types>>
182 where
183 ID: Into<BlockId<Types>> + Send + Sync,
184 {
185 self.data_source.get_header(id).await
186 }
187
188 async fn get_block<ID>(&self, id: ID) -> Fetch<BlockQueryData<Types>>
189 where
190 ID: Into<BlockId<Types>> + Send + Sync,
191 {
192 self.data_source.get_block(id).await
193 }
194 async fn get_payload<ID>(&self, id: ID) -> Fetch<PayloadQueryData<Types>>
195 where
196 ID: Into<BlockId<Types>> + Send + Sync,
197 {
198 self.data_source.get_payload(id).await
199 }
200 async fn get_payload_metadata<ID>(&self, id: ID) -> Fetch<PayloadMetadata<Types>>
201 where
202 ID: Into<BlockId<Types>> + Send + Sync,
203 {
204 self.data_source.get_payload_metadata(id).await
205 }
206 async fn get_vid_common<ID>(&self, id: ID) -> Fetch<VidCommonQueryData<Types>>
207 where
208 ID: Into<BlockId<Types>> + Send + Sync,
209 {
210 self.data_source.get_vid_common(id).await
211 }
212 async fn get_vid_common_metadata<ID>(&self, id: ID) -> Fetch<VidCommonMetadata<Types>>
213 where
214 ID: Into<BlockId<Types>> + Send + Sync,
215 {
216 self.data_source.get_vid_common_metadata(id).await
217 }
218 async fn get_leaf_range<R>(&self, range: R) -> FetchStream<LeafQueryData<Types>>
219 where
220 R: RangeBounds<usize> + Send + 'static,
221 {
222 self.data_source.get_leaf_range(range).await
223 }
224 async fn get_block_range<R>(&self, range: R) -> FetchStream<BlockQueryData<Types>>
225 where
226 R: RangeBounds<usize> + Send + 'static,
227 {
228 self.data_source.get_block_range(range).await
229 }
230
231 async fn get_header_range<R>(&self, range: R) -> FetchStream<Header<Types>>
232 where
233 R: RangeBounds<usize> + Send + 'static,
234 {
235 self.data_source.get_header_range(range).await
236 }
237 async fn get_payload_range<R>(&self, range: R) -> FetchStream<PayloadQueryData<Types>>
238 where
239 R: RangeBounds<usize> + Send + 'static,
240 {
241 self.data_source.get_payload_range(range).await
242 }
243 async fn get_payload_metadata_range<R>(&self, range: R) -> FetchStream<PayloadMetadata<Types>>
244 where
245 R: RangeBounds<usize> + Send + 'static,
246 {
247 self.data_source.get_payload_metadata_range(range).await
248 }
249 async fn get_vid_common_range<R>(&self, range: R) -> FetchStream<VidCommonQueryData<Types>>
250 where
251 R: RangeBounds<usize> + Send + 'static,
252 {
253 self.data_source.get_vid_common_range(range).await
254 }
255 async fn get_vid_common_metadata_range<R>(
256 &self,
257 range: R,
258 ) -> FetchStream<VidCommonMetadata<Types>>
259 where
260 R: RangeBounds<usize> + Send + 'static,
261 {
262 self.data_source.get_vid_common_metadata_range(range).await
263 }
264
265 async fn get_leaf_range_rev(
266 &self,
267 start: Bound<usize>,
268 end: usize,
269 ) -> FetchStream<LeafQueryData<Types>> {
270 self.data_source.get_leaf_range_rev(start, end).await
271 }
272 async fn get_block_range_rev(
273 &self,
274 start: Bound<usize>,
275 end: usize,
276 ) -> FetchStream<BlockQueryData<Types>> {
277 self.data_source.get_block_range_rev(start, end).await
278 }
279 async fn get_payload_range_rev(
280 &self,
281 start: Bound<usize>,
282 end: usize,
283 ) -> FetchStream<PayloadQueryData<Types>> {
284 self.data_source.get_payload_range_rev(start, end).await
285 }
286 async fn get_payload_metadata_range_rev(
287 &self,
288 start: Bound<usize>,
289 end: usize,
290 ) -> FetchStream<PayloadMetadata<Types>> {
291 self.data_source
292 .get_payload_metadata_range_rev(start, end)
293 .await
294 }
295 async fn get_vid_common_range_rev(
296 &self,
297 start: Bound<usize>,
298 end: usize,
299 ) -> FetchStream<VidCommonQueryData<Types>> {
300 self.data_source.get_vid_common_range_rev(start, end).await
301 }
302 async fn get_vid_common_metadata_range_rev(
303 &self,
304 start: Bound<usize>,
305 end: usize,
306 ) -> FetchStream<VidCommonMetadata<Types>> {
307 self.data_source
308 .get_vid_common_metadata_range_rev(start, end)
309 .await
310 }
311 async fn get_block_containing_transaction(
312 &self,
313 h: TransactionHash<Types>,
314 ) -> Fetch<BlockWithTransaction<Types>> {
315 self.data_source.get_block_containing_transaction(h).await
316 }
317
318 async fn get_cert2(&self, height: u64) -> QueryResult<Option<Certificate2<Types>>> {
319 self.data_source.get_cert2(height).await
320 }
321}
322
323impl<D, U, Types> UpdateAvailabilityData<Types> for ExtensibleDataSource<D, U>
324where
325 D: UpdateAvailabilityData<Types> + Send + Sync,
326 U: Send + Sync,
327 Types: NodeType,
328{
329 async fn append(&self, info: BlockInfo<Types>) -> anyhow::Result<()> {
330 self.data_source.append(info).await
331 }
332
333 async fn append_payload(&self, block: BlockQueryData<Types>) -> anyhow::Result<()> {
334 self.data_source.append_payload(block).await
335 }
336}
337
338#[async_trait]
339impl<D, U, Types> NodeDataSource<Types> for ExtensibleDataSource<D, U>
340where
341 D: NodeDataSource<Types> + Send + Sync,
342 U: Send + Sync,
343 Types: NodeType,
344 Header<Types>: QueryableHeader<Types>,
345{
346 async fn block_height(&self) -> QueryResult<usize> {
347 self.data_source.block_height().await
348 }
349 async fn count_transactions_in_range(
350 &self,
351 range: impl RangeBounds<usize> + Send + Sync + Clone,
352 namespace: Option<NamespaceId<Types>>,
353 ) -> QueryResult<usize> {
354 self.data_source
355 .count_transactions_in_range(range, namespace)
356 .await
357 }
358 async fn payload_size_in_range(
359 &self,
360 range: impl RangeBounds<usize> + Send + Sync + Clone,
361 namespace: Option<NamespaceId<Types>>,
362 ) -> QueryResult<usize> {
363 self.data_source
364 .payload_size_in_range(range, namespace)
365 .await
366 }
367 async fn vid_share<ID>(&self, id: ID) -> QueryResult<VidShare>
368 where
369 ID: Into<BlockId<Types>> + Send + Sync,
370 {
371 self.data_source.vid_share(id).await
372 }
373 async fn sync_status(&self) -> QueryResult<SyncStatusQueryData> {
374 self.data_source.sync_status().await
375 }
376 async fn get_header_window(
377 &self,
378 start: impl Into<WindowStart<Types>> + Send + Sync,
379 end: u64,
380 limit: usize,
381 ) -> QueryResult<TimeWindowQueryData<Header<Types>>> {
382 self.data_source.get_header_window(start, end, limit).await
383 }
384}
385
386impl<D, U> HasMetrics for ExtensibleDataSource<D, U>
387where
388 D: HasMetrics,
389{
390 fn metrics(&self) -> &PrometheusMetrics {
391 self.data_source.metrics()
392 }
393}
394
395#[async_trait]
396impl<D, U> StatusDataSource for ExtensibleDataSource<D, U>
397where
398 D: StatusDataSource + Send + Sync,
399 U: Send + Sync,
400{
401 async fn block_height(&self) -> QueryResult<usize> {
402 self.data_source.block_height().await
403 }
404}
405
406#[async_trait]
407impl<D, U, Types, State, const ARITY: usize> MerklizedStateDataSource<Types, State, ARITY>
408 for ExtensibleDataSource<D, U>
409where
410 D: MerklizedStateDataSource<Types, State, ARITY> + Sync,
411 U: Send + Sync,
412 Types: NodeType,
413 State: MerklizedState<Types, ARITY>,
414{
415 async fn get_path(
416 &self,
417 snapshot: Snapshot<Types, State, ARITY>,
418 key: State::Key,
419 ) -> QueryResult<MerkleProof<State::Entry, State::Key, State::T, ARITY>> {
420 self.data_source.get_path(snapshot, key).await
421 }
422}
423
424#[async_trait]
425impl<D, U> MerklizedStateHeightPersistence for ExtensibleDataSource<D, U>
426where
427 D: MerklizedStateHeightPersistence + Sync,
428 U: Send + Sync,
429{
430 async fn get_last_state_height(&self) -> QueryResult<usize> {
431 self.data_source.get_last_state_height().await
432 }
433}
434
435#[async_trait]
436impl<D, U, Types, State, const ARITY: usize> UpdateStateData<Types, State, ARITY>
437 for ExtensibleDataSource<D, U>
438where
439 D: UpdateStateData<Types, State, ARITY> + Send + Sync,
440 U: Send + Sync,
441 State: MerklizedState<Types, ARITY>,
442 Types: NodeType,
443{
444 async fn set_last_state_height(&mut self, height: usize) -> anyhow::Result<()> {
445 self.data_source.set_last_state_height(height).await
446 }
447
448 async fn insert_merkle_nodes(
449 &mut self,
450 path: MerkleProof<State::Entry, State::Key, State::T, ARITY>,
451 traversal_path: Vec<usize>,
452 block_number: u64,
453 ) -> anyhow::Result<()> {
454 self.data_source
455 .insert_merkle_nodes(path, traversal_path, block_number)
456 .await
457 }
458
459 async fn insert_merkle_nodes_batch(
460 &mut self,
461 proofs: Vec<(
462 MerkleProof<State::Entry, State::Key, State::T, ARITY>,
463 Vec<usize>,
464 )>,
465 block_number: u64,
466 ) -> anyhow::Result<()> {
467 self.data_source
468 .insert_merkle_nodes_batch(proofs, block_number)
469 .await
470 }
471}
472
473#[async_trait]
474impl<D, U, Types> ExplorerDataSource<Types> for ExtensibleDataSource<D, U>
475where
476 D: ExplorerDataSource<Types> + Sync,
477 U: Send + Sync,
478 Types: NodeType,
479 Payload<Types>: QueryablePayload<Types>,
480 Header<Types>: ExplorerHeader<Types> + QueryableHeader<Types>,
481 Transaction<Types>: ExplorerTransaction<Types>,
482{
483 async fn get_block_detail(
484 &self,
485 request: explorer::query_data::BlockIdentifier<Types>,
486 ) -> Result<explorer::query_data::BlockDetail<Types>, explorer::query_data::GetBlockDetailError>
487 {
488 self.data_source.get_block_detail(request).await
489 }
490
491 async fn get_block_summaries(
492 &self,
493 request: explorer::query_data::GetBlockSummariesRequest<Types>,
494 ) -> Result<
495 Vec<explorer::query_data::BlockSummary<Types>>,
496 explorer::query_data::GetBlockSummariesError,
497 > {
498 self.data_source.get_block_summaries(request).await
499 }
500
501 async fn get_transaction_detail(
502 &self,
503 request: explorer::query_data::TransactionIdentifier<Types>,
504 ) -> Result<
505 explorer::query_data::TransactionDetailResponse<Types>,
506 explorer::query_data::GetTransactionDetailError,
507 > {
508 self.data_source.get_transaction_detail(request).await
509 }
510
511 async fn get_transaction_summaries(
512 &self,
513 request: explorer::query_data::GetTransactionSummariesRequest<Types>,
514 ) -> Result<
515 Vec<explorer::query_data::TransactionSummary<Types>>,
516 explorer::query_data::GetTransactionSummariesError,
517 > {
518 self.data_source.get_transaction_summaries(request).await
519 }
520
521 async fn get_explorer_summary(
522 &self,
523 ) -> Result<
524 explorer::query_data::ExplorerSummary<Types>,
525 explorer::query_data::GetExplorerSummaryError,
526 > {
527 self.data_source.get_explorer_summary().await
528 }
529
530 async fn get_search_results(
531 &self,
532 query: TaggedBase64,
533 ) -> Result<
534 explorer::query_data::SearchResult<Types>,
535 explorer::query_data::GetSearchResultsError,
536 > {
537 self.data_source.get_search_results(query).await
538 }
539}
540
541#[async_trait]
544impl<D, U, Types> EventsSource<Types> for ExtensibleDataSource<D, U>
545where
546 U: EventsSource<Types> + Sync,
547 D: Send + Sync,
548 Types: NodeType,
549{
550 type EventStream = BoxStream<'static, Arc<Event<Types>>>;
551 type LegacyEventStream = BoxStream<'static, Arc<LegacyEvent<Types>>>;
552
553 async fn get_event_stream(&self, filter: Option<EventFilterSet<Types>>) -> Self::EventStream {
554 Box::pin(self.user_data.get_event_stream(filter).await)
555 }
556
557 async fn get_legacy_event_stream(
558 &self,
559 filter: Option<EventFilterSet<Types>>,
560 ) -> Self::LegacyEventStream {
561 Box::pin(self.user_data.get_legacy_event_stream(filter).await)
562 }
563
564 async fn get_startup_info(&self) -> StartupInfo<Types> {
565 self.user_data.get_startup_info().await
566 }
567}
568
569#[cfg(any(test, feature = "testing"))]
570mod impl_testable_data_source {
571 use hotshot::types::Event;
572 use hotshot_types::new_protocol::CoordinatorEvent;
573
574 use super::*;
575 use crate::{
576 data_source::{UpdateDataSource, fetching::Builder},
577 testing::{
578 consensus::{DataSourceLifeCycle, TestableDataSource},
579 mocks::MockTypes,
580 },
581 };
582
583 #[async_trait]
584 impl<D, U> DataSourceLifeCycle for ExtensibleDataSource<D, U>
585 where
586 D: TestableDataSource + UpdateDataSource<MockTypes>,
587 U: Clone + Default + Send + Sync + 'static,
588 {
589 type Storage = D::Storage;
590 type S = D::S;
591 type P = D::P;
592
593 async fn create(node_id: usize) -> Self::Storage {
594 D::create(node_id).await
595 }
596
597 async fn build(
598 storage: &Self::Storage,
599 opt: impl Send
600 + FnOnce(
601 Builder<MockTypes, Self::S, Self::P>,
602 ) -> Builder<MockTypes, Self::S, Self::P>,
603 ) -> Self {
604 Self::new(D::build(storage, opt).await, Default::default())
605 }
606
607 async fn reset(storage: &Self::Storage) -> Self {
608 Self::new(D::reset(storage).await, Default::default())
609 }
610
611 async fn handle_event(&self, event: &Event<MockTypes>) {
612 let event = CoordinatorEvent::LegacyEvent(event.clone());
613 self.update(&event).await.unwrap();
614 }
615 }
616}
617
618#[cfg(test)]
619mod test {
620 use super::ExtensibleDataSource;
621 use crate::testing::consensus::MockDataSource;
622 use crate::*;
625
626 instantiate_data_source_tests!(ExtensibleDataSource<MockDataSource, ()>);
627}