1use std::{
14 collections::VecDeque,
15 fmt::{Debug, Display},
16 num::{NonZeroUsize, TryFromIntError},
17};
18
19use hotshot_types::traits::{block_contents::BlockHeader, node_implementation::NodeType};
20use serde::{Deserialize, Serialize};
21use tide_disco::StatusCode;
22use time::format_description::well_known::Rfc3339;
23
24use super::{
25 errors::{BadQuery, ExplorerAPIError, InvalidLimit, NotFound, QueryError, Unimplemented},
26 monetary_value::MonetaryValue,
27 traits::{ExplorerHeader, ExplorerTransaction},
28};
29use crate::{
30 Header, Payload, Resolvable, Transaction,
31 availability::{
32 BlockQueryData, NamespaceId, QueryableHeader, QueryablePayload, TransactionHash,
33 },
34 node::BlockHash,
35 types::HeightIndexed,
36};
37
38#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum BlockIdentifier<Types: NodeType> {
47 Latest,
48 Height(usize),
49 Hash(BlockHash<Types>),
50}
51
52impl<Types: NodeType> Display for BlockIdentifier<Types> {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 match self {
55 BlockIdentifier::Latest => write!(f, "latest"),
56 BlockIdentifier::Height(height) => write!(f, "{height}"),
57 BlockIdentifier::Hash(hash) => write!(f, "{hash}"),
58 }
59 }
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
75pub enum TransactionIdentifier<Types: NodeType> {
76 Latest,
77 HeightAndOffset(usize, usize),
78 Hash(TransactionHash<Types>),
79}
80
81impl<Types: NodeType> Display for TransactionIdentifier<Types> {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 match self {
84 TransactionIdentifier::Latest => write!(f, "latest"),
85 TransactionIdentifier::HeightAndOffset(height, offset) => {
86 write!(f, "{height} {offset}")
87 },
88 TransactionIdentifier::Hash(hash) => write!(f, "{hash}"),
89 }
90 }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq)]
105pub struct BlockRange<Types: NodeType> {
106 pub target: BlockIdentifier<Types>,
107 pub num_blocks: NonZeroUsize,
108}
109
110#[derive(Debug, Clone, PartialEq, Eq)]
117pub struct TransactionRange<Types: NodeType> {
118 pub target: TransactionIdentifier<Types>,
119 pub num_transactions: NonZeroUsize,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub struct Timestamp(pub time::OffsetDateTime);
130
131impl Serialize for Timestamp {
132 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
135 let formatted = self.0.format(&Rfc3339).map_err(serde::ser::Error::custom)?;
136 formatted.serialize(serializer)
137 }
138}
139
140impl<'de> Deserialize<'de> for Timestamp {
141 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
144 let s = String::deserialize(deserializer)?;
145 let dt = time::OffsetDateTime::parse(&s, &Rfc3339).map_err(serde::de::Error::custom)?;
146 Ok(Timestamp(dt))
147 }
148}
149
150pub type WalletAddress<Types> = <Header<Types> as ExplorerHeader<Types>>::WalletAddress;
151pub type ProposerId<Types> = <Header<Types> as ExplorerHeader<Types>>::ProposerId;
152pub type BalanceAmount<Types> = <Header<Types> as ExplorerHeader<Types>>::BalanceAmount;
153
154#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
157#[serde(bound = "")]
158pub struct BlockDetail<Types: NodeType>
159where
160 Header<Types>: ExplorerHeader<Types>,
161{
162 pub hash: BlockHash<Types>,
163 pub height: u64,
164 pub time: Timestamp,
165 pub num_transactions: u64,
166 pub proposer_id: ProposerId<Types>,
167 pub fee_recipient: WalletAddress<Types>,
168 pub size: u64,
169 pub block_reward: Vec<MonetaryValue>,
170}
171
172const NANOS_PER_MILLI: i128 = 1_000_000;
176
177impl<Types: NodeType> TryFrom<BlockQueryData<Types>> for BlockDetail<Types>
178where
179 BlockQueryData<Types>: HeightIndexed,
180 Payload<Types>: QueryablePayload<Types>,
181 Header<Types>: BlockHeader<Types> + ExplorerHeader<Types>,
182 BalanceAmount<Types>: Into<MonetaryValue>,
183{
184 type Error = TimestampConversionError;
185
186 fn try_from(value: BlockQueryData<Types>) -> Result<Self, Self::Error> {
187 let milliseconds = i128::from(value.header.timestamp_millis());
188
189 Ok(Self {
190 hash: value.hash(),
191 height: value.height(),
192 time: Timestamp(time::OffsetDateTime::from_unix_timestamp_nanos(
193 milliseconds * NANOS_PER_MILLI,
194 )?),
195 num_transactions: value.num_transactions,
196 proposer_id: value.header().proposer_id(),
197 fee_recipient: value.header().fee_info_account(),
198 size: value.size,
199 block_reward: vec![value.header().fee_info_balance().into()],
200 })
201 }
202}
203
204#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
208#[serde(bound = "")]
209pub struct BlockSummary<Types: NodeType>
210where
211 Header<Types>: ExplorerHeader<Types>,
212{
213 pub hash: BlockHash<Types>,
214 pub height: u64,
215 pub proposer_id: ProposerId<Types>,
216 pub num_transactions: u64,
217 pub size: u64,
218 pub time: Timestamp,
219}
220
221#[derive(Debug, PartialEq, Eq)]
226pub enum TimestampConversionError {
227 TimeError(time::error::ComponentRange),
228 IntError(TryFromIntError),
229}
230
231impl Display for TimestampConversionError {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 match self {
234 TimestampConversionError::TimeError(err) => write!(f, "{err:?}"),
235 TimestampConversionError::IntError(err) => write!(f, "{err:?}"),
236 }
237 }
238}
239
240impl std::error::Error for TimestampConversionError {
241 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
242 match self {
243 TimestampConversionError::TimeError(err) => Some(err),
244 TimestampConversionError::IntError(err) => Some(err),
245 }
246 }
247}
248
249impl From<time::error::ComponentRange> for TimestampConversionError {
250 fn from(value: time::error::ComponentRange) -> Self {
251 Self::TimeError(value)
252 }
253}
254
255impl From<TryFromIntError> for TimestampConversionError {
256 fn from(value: TryFromIntError) -> Self {
257 Self::IntError(value)
258 }
259}
260
261impl From<TimestampConversionError> for crate::QueryError {
262 fn from(value: TimestampConversionError) -> Self {
263 Self::Error {
264 message: format!("{value:?}"),
265 }
266 }
267}
268
269impl<Types: NodeType> TryFrom<BlockQueryData<Types>> for BlockSummary<Types>
270where
271 BlockQueryData<Types>: HeightIndexed,
272 Payload<Types>: QueryablePayload<Types>,
273 Header<Types>: BlockHeader<Types> + ExplorerHeader<Types>,
274{
275 type Error = TimestampConversionError;
276
277 fn try_from(value: BlockQueryData<Types>) -> Result<Self, Self::Error> {
278 let milliseconds = i128::from(value.header.timestamp_millis());
279
280 Ok(Self {
281 hash: value.hash(),
282 height: value.height(),
283 proposer_id: value.header().proposer_id(),
284 num_transactions: value.num_transactions,
285 size: value.size,
286 time: Timestamp(time::OffsetDateTime::from_unix_timestamp_nanos(
287 milliseconds * NANOS_PER_MILLI,
288 )?),
289 })
290 }
291}
292
293#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
302pub struct FeeAttribution {
303 pub target: String,
304 pub fees: Vec<MonetaryValue>,
305}
306
307#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
310#[serde(bound = "")]
311pub struct TransactionDetail<Types: NodeType> {
312 pub hash: TransactionHash<Types>,
313 pub height: u64,
314 pub block_confirmed: bool,
315 pub offset: u64,
316 pub num_transactions: u64,
317 pub size: u64,
318 pub time: Timestamp,
319 pub sequencing_fees: Vec<MonetaryValue>,
320 pub fee_details: Vec<FeeAttribution>,
321}
322
323#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
327#[serde(bound = "")]
328pub struct TransactionDetailResponse<Types: NodeType> {
329 pub details: TransactionDetail<Types>,
330 pub data: Vec<Transaction<Types>>,
331}
332
333#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
338#[serde(bound = "")]
339pub struct TransactionSummary<Types: NodeType>
340where
341 Header<Types>: ExplorerHeader<Types>,
342{
343 pub hash: TransactionHash<Types>,
344 pub rollups: Vec<NamespaceId<Types>>,
345 pub height: u64,
346 pub offset: u64,
347 pub num_transactions: u64,
348 pub time: Timestamp,
349}
350
351impl<Types: NodeType>
352 TryFrom<(
353 &BlockQueryData<Types>,
354 usize,
355 <Types as NodeType>::Transaction,
356 )> for TransactionSummary<Types>
357where
358 BlockQueryData<Types>: HeightIndexed,
359 Payload<Types>: QueryablePayload<Types>,
360 Header<Types>: QueryableHeader<Types> + ExplorerHeader<Types>,
361 Transaction<Types>: ExplorerTransaction<Types>,
362{
363 type Error = TimestampConversionError;
364
365 fn try_from(
366 (block, offset, transaction): (
367 &BlockQueryData<Types>,
368 usize,
369 <Types as NodeType>::Transaction,
370 ),
371 ) -> Result<Self, Self::Error> {
372 let milliseconds = i128::from(block.header.timestamp_millis());
373
374 Ok(Self {
375 hash: transaction.commitment(),
376 height: block.height(),
377 offset: offset as u64,
378 num_transactions: block.num_transactions,
379 time: Timestamp(time::OffsetDateTime::from_unix_timestamp_nanos(
380 milliseconds * NANOS_PER_MILLI,
381 )?),
382 rollups: vec![transaction.namespace_id()],
383 })
384 }
385}
386
387impl<Types: NodeType>
388 TryFrom<(
389 &BlockQueryData<Types>,
390 usize,
391 <Types as NodeType>::Transaction,
392 )> for TransactionDetailResponse<Types>
393where
394 BlockQueryData<Types>: HeightIndexed,
395 Payload<Types>: QueryablePayload<Types>,
396 Header<Types>: QueryableHeader<Types> + ExplorerHeader<Types>,
397 <Types as NodeType>::Transaction: ExplorerTransaction<Types>,
398{
399 type Error = TimestampConversionError;
400
401 fn try_from(
402 (block, offset, transaction): (
403 &BlockQueryData<Types>,
404 usize,
405 <Types as NodeType>::Transaction,
406 ),
407 ) -> Result<Self, Self::Error> {
408 let milliseconds = i128::from(block.header.timestamp_millis());
409
410 Ok(Self {
411 details: TransactionDetail {
412 hash: transaction.commitment(),
413 height: block.height(),
414 block_confirmed: true,
415 offset: offset as u64,
416 num_transactions: block.num_transactions,
417 size: transaction.payload_size(),
418 time: Timestamp(time::OffsetDateTime::from_unix_timestamp_nanos(
419 milliseconds * NANOS_PER_MILLI,
420 )?),
421 sequencing_fees: vec![],
422 fee_details: vec![],
423 },
424 data: vec![transaction],
425 })
426 }
427}
428
429#[derive(Debug, PartialEq, Eq)]
433pub struct GetBlockSummariesRequest<Types: NodeType>(pub BlockRange<Types>);
434
435#[derive(Debug, Deserialize, Serialize)]
438#[serde(bound = "")]
439pub enum TransactionSummaryFilter<Types>
440where
441 Types: NodeType,
442 Header<Types>: QueryableHeader<Types>,
443{
444 None,
445 RollUp(NamespaceId<Types>),
446 Block(usize),
447}
448
449#[derive(Debug)]
454pub struct GetTransactionSummariesRequest<Types>
455where
456 Types: NodeType,
457 Header<Types>: QueryableHeader<Types>,
458{
459 pub range: TransactionRange<Types>,
460 pub filter: TransactionSummaryFilter<Types>,
461}
462
463impl<Types> Default for GetTransactionSummariesRequest<Types>
464where
465 Types: NodeType,
466 Header<Types>: QueryableHeader<Types>,
467{
468 fn default() -> Self {
469 Self {
470 range: TransactionRange {
471 target: TransactionIdentifier::Latest,
472 num_transactions: NonZeroUsize::new(20).unwrap(),
473 },
474 filter: TransactionSummaryFilter::None,
475 }
476 }
477}
478
479#[derive(Debug, Serialize, Deserialize)]
483pub struct GenesisOverview {
484 pub rollups: u64,
485 pub transactions: u64,
486 pub blocks: u64,
487 }
489
490#[derive(Debug, Serialize, Deserialize)]
500pub struct ExplorerHistograms {
501 pub block_time: VecDeque<Option<f64>>,
502 pub block_size: VecDeque<Option<u64>>,
503 pub block_transactions: VecDeque<u64>,
504 pub block_heights: VecDeque<u64>,
505}
506
507#[derive(Debug, Serialize, Deserialize)]
516#[serde(bound = "")]
517pub struct ExplorerSummary<Types: NodeType>
518where
519 Header<Types>: ExplorerHeader<Types>,
520 Transaction<Types>: ExplorerTransaction<Types>,
521{
522 pub latest_block: BlockDetail<Types>,
523 pub genesis_overview: GenesisOverview,
524 pub latest_blocks: Vec<BlockSummary<Types>>,
525 pub latest_transactions: Vec<TransactionSummary<Types>>,
526 pub histograms: ExplorerHistograms,
528}
529
530#[derive(Debug, Serialize, Deserialize)]
534#[serde(bound = "")]
535pub struct SearchResult<Types: NodeType>
536where
537 Header<Types>: ExplorerHeader<Types>,
538 Transaction<Types>: ExplorerTransaction<Types>,
539{
540 pub blocks: Vec<BlockSummary<Types>>,
541 pub transactions: Vec<TransactionSummary<Types>>,
542}
543
544#[derive(Debug, Clone, Serialize, Deserialize)]
547#[serde(untagged)]
548pub enum GetBlockDetailError {
549 Unimplemented(Unimplemented),
550 BlockNotFound(NotFound),
551 QueryError(QueryError),
552}
553
554impl GetBlockDetailError {
555 pub fn status(&self) -> StatusCode {
556 match self {
557 GetBlockDetailError::Unimplemented(err) => err.status(),
558 GetBlockDetailError::QueryError(err) => err.status(),
559 GetBlockDetailError::BlockNotFound(err) => err.status(),
560 }
561 }
562}
563
564impl Display for GetBlockDetailError {
565 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
566 match self {
567 GetBlockDetailError::Unimplemented(err) => write!(f, "{err}"),
568 GetBlockDetailError::QueryError(err) => write!(f, "{err}"),
569 GetBlockDetailError::BlockNotFound(err) => write!(f, "{err}"),
570 }
571 }
572}
573
574impl ExplorerAPIError for GetBlockDetailError {
575 fn code(&self) -> &str {
576 match self {
577 GetBlockDetailError::Unimplemented(err) => err.code(),
578 GetBlockDetailError::QueryError(err) => err.code(),
579 GetBlockDetailError::BlockNotFound(err) => err.code(),
580 }
581 }
582}
583
584impl std::error::Error for GetBlockDetailError {
585 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
586 match self {
587 GetBlockDetailError::Unimplemented(err) => Some(err),
588 GetBlockDetailError::QueryError(err) => Some(err),
589 _ => None,
590 }
591 }
592}
593
594impl From<crate::QueryError> for GetBlockDetailError {
595 fn from(value: crate::QueryError) -> Self {
596 GetBlockDetailError::QueryError(QueryError { error: value })
597 }
598}
599
600#[derive(Debug, Clone, Serialize, Deserialize)]
603#[serde(untagged)]
604pub enum GetBlockSummariesError {
605 Unimplemented(Unimplemented),
606 InvalidLimit(InvalidLimit),
607 TargetNotFound(NotFound),
608 QueryError(QueryError),
609}
610
611impl GetBlockSummariesError {
612 pub fn status(&self) -> StatusCode {
613 match self {
614 GetBlockSummariesError::Unimplemented(err) => err.status(),
615 GetBlockSummariesError::InvalidLimit(err) => err.status(),
616 GetBlockSummariesError::QueryError(err) => err.status(),
617 GetBlockSummariesError::TargetNotFound(err) => err.status(),
618 }
619 }
620}
621
622impl Display for GetBlockSummariesError {
623 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
624 match self {
625 GetBlockSummariesError::Unimplemented(err) => write!(f, "{err}"),
626 GetBlockSummariesError::InvalidLimit(err) => write!(f, "{err}"),
627 GetBlockSummariesError::QueryError(err) => write!(f, "{err}"),
628 GetBlockSummariesError::TargetNotFound(err) => write!(f, "{err}"),
629 }
630 }
631}
632
633impl ExplorerAPIError for GetBlockSummariesError {
634 fn code(&self) -> &str {
635 match self {
636 GetBlockSummariesError::Unimplemented(err) => err.code(),
637 GetBlockSummariesError::InvalidLimit(err) => err.code(),
638 GetBlockSummariesError::QueryError(err) => err.code(),
639 GetBlockSummariesError::TargetNotFound(err) => err.code(),
640 }
641 }
642}
643
644impl std::error::Error for GetBlockSummariesError {
645 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
646 match self {
647 GetBlockSummariesError::Unimplemented(err) => Some(err),
648 GetBlockSummariesError::InvalidLimit(err) => Some(err),
649 GetBlockSummariesError::QueryError(err) => Some(err),
650 _ => None,
651 }
652 }
653}
654
655impl From<crate::QueryError> for GetBlockSummariesError {
656 fn from(value: crate::QueryError) -> Self {
657 GetBlockSummariesError::QueryError(QueryError { error: value })
658 }
659}
660
661#[derive(Debug, Clone, Serialize, Deserialize)]
664#[serde(untagged)]
665pub enum GetTransactionDetailError {
666 Unimplemented(Unimplemented),
667 TransactionNotFound(NotFound),
668 QueryError(QueryError),
669}
670
671impl GetTransactionDetailError {
672 pub fn status(&self) -> StatusCode {
673 match self {
674 GetTransactionDetailError::Unimplemented(err) => err.status(),
675 GetTransactionDetailError::QueryError(err) => err.status(),
676 GetTransactionDetailError::TransactionNotFound(err) => err.status(),
677 }
678 }
679}
680
681impl Display for GetTransactionDetailError {
682 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
683 match self {
684 GetTransactionDetailError::Unimplemented(err) => write!(f, "{err}"),
685 GetTransactionDetailError::QueryError(err) => write!(f, "{err}"),
686 GetTransactionDetailError::TransactionNotFound(err) => write!(f, "{err}"),
687 }
688 }
689}
690
691impl ExplorerAPIError for GetTransactionDetailError {
692 fn code(&self) -> &str {
693 match self {
694 GetTransactionDetailError::Unimplemented(err) => err.code(),
695 GetTransactionDetailError::QueryError(err) => err.code(),
696 GetTransactionDetailError::TransactionNotFound(err) => err.code(),
697 }
698 }
699}
700
701impl std::error::Error for GetTransactionDetailError {
702 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
703 match self {
704 GetTransactionDetailError::Unimplemented(err) => Some(err),
705 GetTransactionDetailError::QueryError(err) => Some(err),
706 _ => None,
707 }
708 }
709}
710
711impl From<crate::QueryError> for GetTransactionDetailError {
714 fn from(value: crate::QueryError) -> Self {
715 GetTransactionDetailError::QueryError(QueryError { error: value })
716 }
717}
718
719impl From<TimestampConversionError> for GetTransactionDetailError {
720 fn from(value: TimestampConversionError) -> Self {
721 GetTransactionDetailError::QueryError(QueryError {
722 error: value.into(),
723 })
724 }
725}
726
727#[derive(Debug, Clone, Serialize, Deserialize)]
730#[serde(untagged)]
731pub enum GetTransactionSummariesError {
732 Unimplemented(Unimplemented),
733 InvalidLimit(InvalidLimit),
734 TargetNotFound(NotFound),
735 QueryError(QueryError),
736}
737
738impl GetTransactionSummariesError {
739 pub fn status(&self) -> StatusCode {
740 match self {
741 GetTransactionSummariesError::Unimplemented(err) => err.status(),
742 GetTransactionSummariesError::InvalidLimit(err) => err.status(),
743 GetTransactionSummariesError::QueryError(err) => err.status(),
744 GetTransactionSummariesError::TargetNotFound(err) => err.status(),
745 }
746 }
747}
748
749impl Display for GetTransactionSummariesError {
750 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
751 match self {
752 GetTransactionSummariesError::Unimplemented(err) => write!(f, "{err}"),
753 GetTransactionSummariesError::InvalidLimit(err) => write!(f, "{err}"),
754 GetTransactionSummariesError::QueryError(err) => write!(f, "{err}"),
755 GetTransactionSummariesError::TargetNotFound(err) => write!(f, "{err}"),
756 }
757 }
758}
759
760impl ExplorerAPIError for GetTransactionSummariesError {
761 fn code(&self) -> &str {
762 match self {
763 GetTransactionSummariesError::Unimplemented(err) => err.code(),
764 GetTransactionSummariesError::InvalidLimit(err) => err.code(),
765 GetTransactionSummariesError::QueryError(err) => err.code(),
766 GetTransactionSummariesError::TargetNotFound(err) => err.code(),
767 }
768 }
769}
770
771impl std::error::Error for GetTransactionSummariesError {
772 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
773 match self {
774 GetTransactionSummariesError::Unimplemented(err) => Some(err),
775 GetTransactionSummariesError::InvalidLimit(err) => Some(err),
776 GetTransactionSummariesError::QueryError(err) => Some(err),
777 _ => None,
778 }
779 }
780}
781
782impl From<crate::QueryError> for GetTransactionSummariesError {
783 fn from(value: crate::QueryError) -> Self {
784 GetTransactionSummariesError::QueryError(QueryError { error: value })
785 }
786}
787
788#[derive(Debug, Clone, Serialize, Deserialize)]
791#[serde(untagged)]
792pub enum GetExplorerSummaryError {
793 Unimplemented(Unimplemented),
794 QueryError(QueryError),
795 GetBlockDetailError(GetBlockDetailError),
796 GetBlockSummariesError(GetBlockSummariesError),
797 GetTransactionSummariesError(GetTransactionSummariesError),
798}
799
800impl GetExplorerSummaryError {
801 pub fn status(&self) -> StatusCode {
802 match self {
803 GetExplorerSummaryError::QueryError(err) => err.status(),
804 GetExplorerSummaryError::Unimplemented(err) => err.status(),
805 GetExplorerSummaryError::GetBlockDetailError(err) => err.status(),
806 GetExplorerSummaryError::GetBlockSummariesError(err) => err.status(),
807 GetExplorerSummaryError::GetTransactionSummariesError(err) => err.status(),
808 }
809 }
810}
811
812impl Display for GetExplorerSummaryError {
813 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
814 match self {
815 GetExplorerSummaryError::QueryError(err) => write!(f, "{err}"),
816 GetExplorerSummaryError::Unimplemented(err) => write!(f, "{err}"),
817 GetExplorerSummaryError::GetBlockDetailError(err) => write!(f, "{err}"),
818 GetExplorerSummaryError::GetBlockSummariesError(err) => write!(f, "{err}"),
819 GetExplorerSummaryError::GetTransactionSummariesError(err) => write!(f, "{err}"),
820 }
821 }
822}
823
824impl ExplorerAPIError for GetExplorerSummaryError {
825 fn code(&self) -> &str {
826 match self {
827 GetExplorerSummaryError::QueryError(err) => err.code(),
828 GetExplorerSummaryError::Unimplemented(err) => err.code(),
829 GetExplorerSummaryError::GetBlockDetailError(err) => err.code(),
830 GetExplorerSummaryError::GetBlockSummariesError(err) => err.code(),
831 GetExplorerSummaryError::GetTransactionSummariesError(err) => err.code(),
832 }
833 }
834}
835
836impl std::error::Error for GetExplorerSummaryError {
837 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
838 match self {
839 GetExplorerSummaryError::Unimplemented(err) => Some(err),
840 GetExplorerSummaryError::QueryError(err) => Some(err),
841 GetExplorerSummaryError::GetBlockDetailError(err) => Some(err),
842 GetExplorerSummaryError::GetBlockSummariesError(err) => Some(err),
843 GetExplorerSummaryError::GetTransactionSummariesError(err) => Some(err),
844 }
845 }
846}
847
848impl From<crate::QueryError> for GetExplorerSummaryError {
851 fn from(value: crate::QueryError) -> Self {
852 GetExplorerSummaryError::QueryError(QueryError { error: value })
853 }
854}
855
856impl From<GetBlockDetailError> for GetExplorerSummaryError {
857 fn from(value: GetBlockDetailError) -> Self {
858 GetExplorerSummaryError::GetBlockDetailError(value)
859 }
860}
861
862impl From<GetBlockSummariesError> for GetExplorerSummaryError {
863 fn from(value: GetBlockSummariesError) -> Self {
864 GetExplorerSummaryError::GetBlockSummariesError(value)
865 }
866}
867
868impl From<GetTransactionSummariesError> for GetExplorerSummaryError {
869 fn from(value: GetTransactionSummariesError) -> Self {
870 GetExplorerSummaryError::GetTransactionSummariesError(value)
871 }
872}
873
874#[derive(Debug, Clone, Serialize, Deserialize)]
877#[serde(untagged)]
878pub enum GetSearchResultsError {
879 Unimplemented(Unimplemented),
880 QueryError(QueryError),
881 InvalidQuery(BadQuery),
882}
883
884impl GetSearchResultsError {
885 pub fn status(&self) -> StatusCode {
886 match self {
887 GetSearchResultsError::QueryError(err) => err.status(),
888 GetSearchResultsError::Unimplemented(err) => err.status(),
889 GetSearchResultsError::InvalidQuery(err) => err.status(),
890 }
891 }
892}
893
894impl Display for GetSearchResultsError {
895 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
896 match self {
897 GetSearchResultsError::QueryError(err) => write!(f, "{err}"),
898 GetSearchResultsError::Unimplemented(err) => write!(f, "{err}"),
899 GetSearchResultsError::InvalidQuery(err) => write!(f, "{err}"),
900 }
901 }
902}
903
904impl ExplorerAPIError for GetSearchResultsError {
905 fn code(&self) -> &str {
906 match self {
907 GetSearchResultsError::QueryError(err) => err.code(),
908 GetSearchResultsError::Unimplemented(err) => err.code(),
909 GetSearchResultsError::InvalidQuery(err) => err.code(),
910 }
911 }
912}
913
914impl std::error::Error for GetSearchResultsError {
915 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
916 match self {
917 GetSearchResultsError::Unimplemented(err) => Some(err),
918 GetSearchResultsError::QueryError(err) => Some(err),
919 GetSearchResultsError::InvalidQuery(err) => Some(err),
920 }
921 }
922}
923
924impl From<crate::QueryError> for GetSearchResultsError {
925 fn from(value: crate::QueryError) -> Self {
926 GetSearchResultsError::QueryError(QueryError { error: value })
927 }
928}