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
use cfx_types::{H256, U256};
use primitives::{
    receipt::Receipt, SignedTransaction, TransactionIndex, TransactionStatus,
};

use super::super::ConsensusGraph;

pub struct TransactionInfo {
    pub tx_index: TransactionIndex,
    pub maybe_executed_extra_info: Option<MaybeExecutedTxExtraInfo>,
}

pub struct MaybeExecutedTxExtraInfo {
    pub receipt: Receipt,
    pub block_number: u64,
    pub prior_gas_used: U256,
    pub tx_exec_error_msg: Option<String>,
}

impl ConsensusGraph {
    pub fn get_transaction_info_by_hash(
        &self, hash: &H256,
    ) -> Option<(SignedTransaction, TransactionInfo)> {
        // We need to hold the inner lock to ensure that tx_index and receipts
        // are consistent

        let tx_info = self.get_transaction_info(hash)?;
        if let Some(executed) = &tx_info.maybe_executed_extra_info {
            if executed.receipt.outcome_status == TransactionStatus::Skipped {
                // A skipped transaction is not visible to clients if
                // accessed by its hash.
                return None;
            }
        }
        let block = self.data_man.block_by_hash(
            &tx_info.tx_index.block_hash,
            false, /* update_cache */
        )?;
        let transaction =
            (*block.transactions[tx_info.tx_index.real_index]).clone();
        Some((transaction, tx_info))
    }

    fn get_transaction_info(&self, tx_hash: &H256) -> Option<TransactionInfo> {
        let inner = self.inner.read();

        trace!("Get receipt with tx_hash {}", tx_hash);
        let tx_index = self.data_man.transaction_index_by_hash(
            tx_hash, false, /* update_cache */
        )?;
        // receipts should never be None if transaction index isn't none.
        let maybe_executed_extra_info = inner
            .block_execution_results_by_hash(
                &tx_index.block_hash,
                false, /* update_cache */
            )
            .map(|receipt| {
                let block_receipts = receipt.1.block_receipts;

                let prior_gas_used = if tx_index.real_index == 0 {
                    U256::zero()
                } else {
                    block_receipts.receipts[tx_index.real_index - 1]
                        .accumulated_gas_used
                };
                let tx_exec_error_msg = block_receipts
                    .tx_execution_error_messages[tx_index.real_index]
                    .clone();

                MaybeExecutedTxExtraInfo {
                    receipt: block_receipts
                        .receipts
                        .get(tx_index.real_index)
                        .expect("Error: can't get receipt by tx_index ")
                        .clone(),
                    block_number: block_receipts.block_number,
                    prior_gas_used,
                    tx_exec_error_msg: if tx_exec_error_msg.is_empty() {
                        None
                    } else {
                        Some(tx_exec_error_msg.clone())
                    },
                }
            });

        Some(TransactionInfo {
            tx_index,
            maybe_executed_extra_info,
        })
    }
}