cfxcore/consensus/consensus_graph/rpc_api/
transaction_provider.rs

1use cfx_types::{H256, U256};
2use primitives::{
3    receipt::Receipt, SignedTransaction, TransactionIndex, TransactionStatus,
4};
5
6use super::super::ConsensusGraph;
7
8pub struct TransactionInfo {
9    pub tx_index: TransactionIndex,
10    pub maybe_executed_extra_info: Option<MaybeExecutedTxExtraInfo>,
11}
12
13pub struct MaybeExecutedTxExtraInfo {
14    pub receipt: Receipt,
15    pub block_number: u64,
16    pub prior_gas_used: U256,
17    pub tx_exec_error_msg: Option<String>,
18}
19
20impl ConsensusGraph {
21    pub fn get_signed_tx_and_tx_info(
22        &self, hash: &H256,
23    ) -> Option<(SignedTransaction, TransactionInfo)> {
24        // We need to hold the inner lock to ensure that tx_index and receipts
25        // are consistent
26
27        let tx_info = self.get_transaction_info(hash)?;
28        if let Some(executed) = &tx_info.maybe_executed_extra_info {
29            if executed.receipt.outcome_status == TransactionStatus::Skipped {
30                // A skipped transaction is not visible to clients if
31                // accessed by its hash.
32                return None;
33            }
34        }
35        let block = self.data_man.block_by_hash(
36            &tx_info.tx_index.block_hash,
37            false, /* update_cache */
38        )?;
39        let transaction =
40            (*block.transactions[tx_info.tx_index.real_index]).clone();
41        Some((transaction, tx_info))
42    }
43
44    fn get_transaction_info(&self, tx_hash: &H256) -> Option<TransactionInfo> {
45        let inner = self.inner.read();
46
47        trace!("Get receipt with tx_hash {}", tx_hash);
48        let tx_index = self.data_man.transaction_index_by_hash(
49            tx_hash, false, /* update_cache */
50        )?;
51        // receipts should never be None if transaction index isn't none.
52        let maybe_executed_extra_info = inner
53            .block_execution_results_by_hash(
54                &tx_index.block_hash,
55                false, /* update_cache */
56            )
57            .map(|receipt| {
58                let block_receipts = receipt.1.block_receipts;
59
60                let prior_gas_used = if tx_index.real_index == 0 {
61                    U256::zero()
62                } else {
63                    block_receipts.receipts[tx_index.real_index - 1]
64                        .accumulated_gas_used
65                };
66                let tx_exec_error_msg = block_receipts
67                    .tx_execution_error_messages[tx_index.real_index]
68                    .clone();
69
70                MaybeExecutedTxExtraInfo {
71                    receipt: block_receipts
72                        .receipts
73                        .get(tx_index.real_index)
74                        .expect("Error: can't get receipt by tx_index ")
75                        .clone(),
76                    block_number: block_receipts.block_number,
77                    prior_gas_used,
78                    tx_exec_error_msg: if tx_exec_error_msg.is_empty() {
79                        None
80                    } else {
81                        Some(tx_exec_error_msg.clone())
82                    },
83                }
84            });
85
86        Some(TransactionInfo {
87            tx_index,
88            maybe_executed_extra_info,
89        })
90    }
91}