1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::{BlockNumReader, BlockReader};
use alloy_eips::BlockHashOrNumber;
use alloy_primitives::{Address, BlockNumber, TxHash, TxNumber};
use reth_primitives::{TransactionMeta, TransactionSigned, TransactionSignedNoHash};
use reth_storage_errors::provider::{ProviderError, ProviderResult};
use std::ops::{Range, RangeBounds, RangeInclusive};

/// Enum to control transaction hash inclusion.
///
/// This serves as a hint to the provider to include or omit exclude hashes because hashes are
/// stored separately and are not always needed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum TransactionVariant {
    /// Indicates that transactions should be processed without including their hashes.
    NoHash,
    /// Indicates that transactions should be processed along with their hashes.
    #[default]
    WithHash,
}

///  Client trait for fetching [TransactionSigned] related data.
#[auto_impl::auto_impl(&, Arc)]
pub trait TransactionsProvider: BlockNumReader + Send + Sync {
    /// Get internal transaction identifier by transaction hash.
    ///
    /// This is the inverse of [TransactionsProvider::transaction_by_id].
    /// Returns None if the transaction is not found.
    fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>>;

    /// Get transaction by id, computes hash every time so more expensive.
    fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<TransactionSigned>>;

    /// Get transaction by id without computing the hash.
    fn transaction_by_id_no_hash(
        &self,
        id: TxNumber,
    ) -> ProviderResult<Option<TransactionSignedNoHash>>;

    /// Get transaction by transaction hash.
    fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<TransactionSigned>>;

    /// Get transaction by transaction hash and additional metadata of the block the transaction was
    /// mined in
    fn transaction_by_hash_with_meta(
        &self,
        hash: TxHash,
    ) -> ProviderResult<Option<(TransactionSigned, TransactionMeta)>>;

    /// Get transaction block number
    fn transaction_block(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>>;

    /// Get transactions by block id.
    fn transactions_by_block(
        &self,
        block: BlockHashOrNumber,
    ) -> ProviderResult<Option<Vec<TransactionSigned>>>;

    /// Get transactions by block range.
    fn transactions_by_block_range(
        &self,
        range: impl RangeBounds<BlockNumber>,
    ) -> ProviderResult<Vec<Vec<TransactionSigned>>>;

    /// Get transactions by tx range.
    fn transactions_by_tx_range(
        &self,
        range: impl RangeBounds<TxNumber>,
    ) -> ProviderResult<Vec<TransactionSignedNoHash>>;

    /// Get Senders from a tx range.
    fn senders_by_tx_range(
        &self,
        range: impl RangeBounds<TxNumber>,
    ) -> ProviderResult<Vec<Address>>;

    /// Get transaction sender.
    ///
    /// Returns None if the transaction is not found.
    fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>>;
}

///  Client trait for fetching additional [TransactionSigned] related data.
#[auto_impl::auto_impl(&, Arc)]
pub trait TransactionsProviderExt: BlockReader + Send + Sync {
    /// Get transactions range by block range.
    fn transaction_range_by_block_range(
        &self,
        block_range: RangeInclusive<BlockNumber>,
    ) -> ProviderResult<RangeInclusive<TxNumber>> {
        let from = self
            .block_body_indices(*block_range.start())?
            .ok_or(ProviderError::BlockBodyIndicesNotFound(*block_range.start()))?
            .first_tx_num();

        let to = self
            .block_body_indices(*block_range.end())?
            .ok_or(ProviderError::BlockBodyIndicesNotFound(*block_range.end()))?
            .last_tx_num();

        Ok(from..=to)
    }

    /// Get transaction hashes from a transaction range.
    fn transaction_hashes_by_range(
        &self,
        tx_range: Range<TxNumber>,
    ) -> ProviderResult<Vec<(TxHash, TxNumber)>>;
}