LCOV - code coverage report
Current view: top level - src/node - transaction.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 83 88 94.3 %
Date: 2022-04-21 14:51:19 Functions: 4 4 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 47 50 94.0 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2021 The Bitcoin Core developers
#       3                 :            : // Distributed under the MIT software license, see the accompanying
#       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5                 :            : 
#       6                 :            : #include <consensus/validation.h>
#       7                 :            : #include <index/txindex.h>
#       8                 :            : #include <net.h>
#       9                 :            : #include <net_processing.h>
#      10                 :            : #include <node/blockstorage.h>
#      11                 :            : #include <node/context.h>
#      12                 :            : #include <txmempool.h>
#      13                 :            : #include <validation.h>
#      14                 :            : #include <validationinterface.h>
#      15                 :            : #include <node/transaction.h>
#      16                 :            : 
#      17                 :            : #include <future>
#      18                 :            : 
#      19                 :            : namespace node {
#      20                 :            : static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out)
#      21                 :       4308 : {
#      22                 :       4308 :     err_string_out = state.ToString();
#      23         [ +  - ]:       4308 :     if (state.IsInvalid()) {
#      24         [ +  + ]:       4308 :         if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
#      25                 :         18 :             return TransactionError::MISSING_INPUTS;
#      26                 :         18 :         }
#      27                 :       4290 :         return TransactionError::MEMPOOL_REJECTED;
#      28                 :       4308 :     } else {
#      29                 :          0 :         return TransactionError::MEMPOOL_ERROR;
#      30                 :          0 :     }
#      31                 :       4308 : }
#      32                 :            : 
#      33                 :            : TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
#      34                 :      13661 : {
#      35                 :            :     // BroadcastTransaction can be called by either sendrawtransaction RPC or the wallet.
#      36                 :            :     // chainman, mempool and peerman are initialized before the RPC server and wallet are started
#      37                 :            :     // and reset after the RPC sever and wallet are stopped.
#      38                 :      13661 :     assert(node.chainman);
#      39                 :          0 :     assert(node.mempool);
#      40                 :          0 :     assert(node.peerman);
#      41                 :            : 
#      42                 :          0 :     std::promise<void> promise;
#      43                 :      13661 :     uint256 txid = tx->GetHash();
#      44                 :      13661 :     uint256 wtxid = tx->GetWitnessHash();
#      45                 :      13661 :     bool callback_set = false;
#      46                 :            : 
#      47                 :      13661 :     {
#      48                 :      13661 :         LOCK(cs_main);
#      49                 :            : 
#      50                 :            :         // If the transaction is already confirmed in the chain, don't do anything
#      51                 :            :         // and return early.
#      52                 :      13661 :         CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
#      53         [ +  + ]:      98786 :         for (size_t o = 0; o < tx->vout.size(); o++) {
#      54                 :      85133 :             const Coin& existingCoin = view.AccessCoin(COutPoint(txid, o));
#      55                 :            :             // IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
#      56                 :            :             // So if the output does exist, then this transaction exists in the chain.
#      57         [ +  + ]:      85133 :             if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
#      58                 :      85133 :         }
#      59                 :            : 
#      60         [ +  + ]:      13653 :         if (auto mempool_tx = node.mempool->get(txid); mempool_tx) {
#      61                 :            :             // There's already a transaction in the mempool with this txid. Don't
#      62                 :            :             // try to submit this transaction to the mempool (since it'll be
#      63                 :            :             // rejected as a TX_CONFLICT), but do attempt to reannounce the mempool
#      64                 :            :             // transaction if relay=true.
#      65                 :            :             //
#      66                 :            :             // The mempool transaction may have the same or different witness (and
#      67                 :            :             // wtxid) as this transaction. Use the mempool's wtxid for reannouncement.
#      68                 :         72 :             wtxid = mempool_tx->GetWitnessHash();
#      69                 :      13581 :         } else {
#      70                 :            :             // Transaction is not already in the mempool.
#      71         [ +  + ]:      13581 :             if (max_tx_fee > 0) {
#      72                 :            :                 // First, call ATMP with test_accept and check the fee. If ATMP
#      73                 :            :                 // fails here, return error immediately.
#      74                 :       4596 :                 const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ true);
#      75         [ +  + ]:       4596 :                 if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
#      76                 :        499 :                     return HandleATMPError(result.m_state, err_string);
#      77         [ +  + ]:       4097 :                 } else if (result.m_base_fees.value() > max_tx_fee) {
#      78                 :          4 :                     return TransactionError::MAX_FEE_EXCEEDED;
#      79                 :          4 :                 }
#      80                 :       4596 :             }
#      81                 :            :             // Try to submit the transaction to the mempool.
#      82                 :      13078 :             const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ false);
#      83         [ +  + ]:      13078 :             if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
#      84                 :       3809 :                 return HandleATMPError(result.m_state, err_string);
#      85                 :       3809 :             }
#      86                 :            : 
#      87                 :            :             // Transaction was accepted to the mempool.
#      88                 :            : 
#      89         [ +  + ]:       9269 :             if (relay) {
#      90                 :            :                 // the mempool tracks locally submitted transactions to make a
#      91                 :            :                 // best-effort of initial broadcast
#      92                 :       9260 :                 node.mempool->AddUnbroadcastTx(txid);
#      93                 :       9260 :             }
#      94                 :            : 
#      95         [ +  + ]:       9269 :             if (wait_callback) {
#      96                 :            :                 // For transactions broadcast from outside the wallet, make sure
#      97                 :            :                 // that the wallet has been notified of the transaction before
#      98                 :            :                 // continuing.
#      99                 :            :                 //
#     100                 :            :                 // This prevents a race where a user might call sendrawtransaction
#     101                 :            :                 // with a transaction to/from their wallet, immediately call some
#     102                 :            :                 // wallet RPC, and get a stale result because callbacks have not
#     103                 :            :                 // yet been processed.
#     104                 :       6962 :                 CallFunctionInValidationInterfaceQueue([&promise] {
#     105                 :       6962 :                     promise.set_value();
#     106                 :       6962 :                 });
#     107                 :       6962 :                 callback_set = true;
#     108                 :       6962 :             }
#     109                 :       9269 :         }
#     110                 :      13653 :     } // cs_main
#     111                 :            : 
#     112         [ +  + ]:       9341 :     if (callback_set) {
#     113                 :            :         // Wait until Validation Interface clients have been notified of the
#     114                 :            :         // transaction entering the mempool.
#     115                 :       6962 :         promise.get_future().wait();
#     116                 :       6962 :     }
#     117                 :            : 
#     118         [ +  + ]:       9341 :     if (relay) {
#     119                 :       9265 :         node.peerman->RelayTransaction(txid, wtxid);
#     120                 :       9265 :     }
#     121                 :            : 
#     122                 :       9341 :     return TransactionError::OK;
#     123                 :      13653 : }
#     124                 :            : 
#     125                 :            : CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock)
#     126                 :       1074 : {
#     127 [ +  + ][ +  + ]:       1074 :     if (mempool && !block_index) {
#     128                 :        964 :         CTransactionRef ptx = mempool->get(hash);
#     129         [ +  + ]:        964 :         if (ptx) return ptx;
#     130                 :        964 :     }
#     131         [ +  + ]:        138 :     if (g_txindex) {
#     132                 :         22 :         CTransactionRef tx;
#     133                 :         22 :         uint256 block_hash;
#     134         [ +  - ]:         22 :         if (g_txindex->FindTx(hash, block_hash, tx)) {
#     135 [ +  + ][ +  + ]:         22 :             if (!block_index || block_index->GetBlockHash() == block_hash) {
#                 [ +  + ]
#     136                 :            :                 // Don't return the transaction if the provided block hash doesn't match.
#     137                 :            :                 // The case where a transaction appears in multiple blocks (e.g. reorgs or
#     138                 :            :                 // BIP30) is handled by the block lookup below.
#     139                 :         20 :                 hashBlock = block_hash;
#     140                 :         20 :                 return tx;
#     141                 :         20 :             }
#     142                 :         22 :         }
#     143                 :         22 :     }
#     144         [ +  + ]:        118 :     if (block_index) {
#     145                 :        103 :         CBlock block;
#     146         [ +  - ]:        103 :         if (ReadBlockFromDisk(block, block_index, consensusParams)) {
#     147         [ +  + ]:        274 :             for (const auto& tx : block.vtx) {
#     148         [ +  + ]:        274 :                 if (tx->GetHash() == hash) {
#     149                 :         99 :                     hashBlock = block_index->GetBlockHash();
#     150                 :         99 :                     return tx;
#     151                 :         99 :                 }
#     152                 :        274 :             }
#     153                 :        103 :         }
#     154                 :        103 :     }
#     155                 :         19 :     return nullptr;
#     156                 :        118 : }
#     157                 :            : } // namespace node

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a