LCOV - code coverage report
Current view: top level - src/node - transaction.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 100.0 % 71 71
Test Date: 2026-10-09 06:24:36 Functions: 100.0 % 3 3
Branches: 76.2 % 101 77

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2010 Satoshi Nakamoto
       2                 :             : // Copyright (c) 2009-present 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 <node/transaction.h>
       7                 :             : 
       8                 :             : #include <consensus/validation.h>
       9                 :             : #include <index/txindex.h>
      10                 :             : #include <net.h>
      11                 :             : #include <net_processing.h>
      12                 :             : #include <node/blockstorage.h>
      13                 :             : #include <node/context.h>
      14                 :             : #include <node/types.h>
      15                 :             : #include <policy/feerate.h>
      16                 :             : #include <txmempool.h>
      17                 :             : #include <validation.h>
      18                 :             : #include <validationinterface.h>
      19                 :             : 
      20                 :             : namespace node {
      21                 :        4487 : static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out)
      22                 :             : {
      23                 :        4487 :     err_string_out = state.ToString();
      24         [ +  - ]:        4487 :     if (state.IsInvalid()) {
      25         [ +  + ]:        4487 :         if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
      26                 :             :             return TransactionError::MISSING_INPUTS;
      27                 :             :         }
      28                 :        4478 :         return TransactionError::MEMPOOL_REJECTED;
      29                 :             :     } else {
      30                 :             :         return TransactionError::MEMPOOL_ERROR;
      31                 :             :     }
      32                 :             : }
      33                 :             : 
      34                 :       39458 : TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, const CFeeRate& max_tx_fee_rate, TxBroadcast broadcast_method, bool wait_callback)
      35                 :             : {
      36                 :             :     // BroadcastTransaction can be called by RPC or by the wallet.
      37                 :             :     // chainman, mempool and peerman are initialized before the RPC server and wallet are started
      38                 :             :     // and reset after the RPC sever and wallet are stopped.
      39         [ -  + ]:       39458 :     assert(node.chainman);
      40         [ -  + ]:       39458 :     assert(node.mempool);
      41         [ -  + ]:       39458 :     assert(node.peerman);
      42                 :             : 
      43                 :       39458 :     Txid txid = tx->GetHash();
      44                 :       39458 :     Wtxid wtxid = tx->GetWitnessHash();
      45                 :       39458 :     bool callback_set = false;
      46                 :             : 
      47                 :       39458 :     {
      48                 :       39458 :         LOCK(cs_main);
      49                 :             : 
      50                 :             :         // If the transaction is already confirmed in the chain, don't do anything
      51                 :             :         // and return early.
      52   [ +  -  +  - ]:       39458 :         CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
      53   [ -  +  +  + ]:      123328 :         for (size_t o = 0; o < tx->vout.size(); o++) {
      54         [ +  - ]:       83873 :             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         [ +  + ]:       83873 :             if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_UTXO_SET;
      58                 :             :         }
      59                 :             : 
      60   [ +  -  +  + ]:       39455 :         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 broadcast_method is not TxBroadcast::MEMPOOL_NO_BROADCAST.
      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                 :        8951 :             wtxid = mempool_tx->GetWitnessHash();
      69                 :             :         } else {
      70                 :             :             // Transaction is not already in the mempool.
      71                 :       30504 :             const bool check_max_fee{max_tx_fee > 0};
      72         [ +  + ]:       30504 :             const bool check_max_feerate{max_tx_fee_rate > CFeeRate(0)};
      73   [ +  +  +  + ]:       30504 :             if (check_max_fee || check_max_feerate || broadcast_method == TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST) {
      74                 :             :                 // First, call ATMP with test_accept and check the fee. If ATMP
      75                 :             :                 // fails here, return error immediately.
      76         [ +  - ]:       16446 :                 const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ true);
      77         [ +  + ]:       16446 :                 if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
      78         [ +  - ]:         143 :                     return HandleATMPError(result.m_state, err_string);
      79   [ +  +  +  - ]:       18003 :                 } else if (check_max_fee && result.m_base_fees.value() > max_tx_fee) {
      80                 :             :                     return TransactionError::MAX_FEE_EXCEEDED;
      81   [ +  +  +  -  :       32605 :                 } else if (check_max_feerate && result.m_base_fees.value() > max_tx_fee_rate.GetFee(result.m_vsize.value())) {
             +  -  +  + ]
      82                 :             :                     return TransactionError::MAX_FEE_RATE_EXCEEDED;
      83                 :             :                 }
      84                 :       16446 :             }
      85                 :             : 
      86         [ +  + ]:       30357 :             switch (broadcast_method) {
      87                 :       20340 :             case TxBroadcast::MEMPOOL_NO_BROADCAST:
      88                 :       20340 :             case TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL:
      89                 :             :                 // Try to submit the transaction to the mempool.
      90                 :       20340 :                 {
      91                 :       20340 :                     const MempoolAcceptResult result =
      92         [ +  - ]:       20340 :                         node.chainman->ProcessTransaction(tx, /*test_accept=*/false);
      93         [ +  + ]:       20340 :                     if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
      94         [ +  - ]:        4344 :                         return HandleATMPError(result.m_state, err_string);
      95                 :             :                     }
      96                 :       20340 :                 }
      97                 :             :                 // Transaction was accepted to the mempool.
      98                 :             : 
      99         [ +  + ]:       15996 :                 if (broadcast_method == TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL) {
     100                 :             :                     // the mempool tracks locally submitted transactions to make a
     101                 :             :                     // best-effort of initial broadcast
     102         [ +  - ]:       15970 :                     node.mempool->AddUnbroadcastTx(txid);
     103                 :             :                 }
     104                 :             :                 break;
     105                 :             :             case TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST:
     106                 :             :                 break;
     107                 :             :             }
     108                 :             : 
     109   [ +  +  -  + ]:       26013 :             if (wait_callback && node.validation_signals) {
     110                 :             :                 // For transactions broadcast from outside the wallet, make sure
     111                 :             :                 // that the wallet has been notified of the transaction before
     112                 :             :                 // continuing.
     113                 :             :                 //
     114                 :             :                 // This prevents a race where a user might call sendrawtransaction
     115                 :             :                 // with a transaction to/from their wallet, immediately call some
     116                 :             :                 // wallet RPC, and get a stale result because callbacks have not
     117                 :             :                 // yet been processed.
     118                 :             :                 callback_set = true;
     119                 :             :             }
     120         [ +  - ]:       39455 :         }
     121                 :        4494 :     } // cs_main
     122                 :             : 
     123         [ +  + ]:       34964 :     if (callback_set) {
     124                 :             :         // Wait until Validation Interface clients have been notified of the
     125                 :             :         // transaction entering the mempool.
     126                 :       24315 :         node.validation_signals->SyncWithValidationInterfaceQueue();
     127                 :             :     }
     128                 :             : 
     129      [ +  +  + ]:       34964 :     switch (broadcast_method) {
     130                 :             :     case TxBroadcast::MEMPOOL_NO_BROADCAST:
     131                 :             :         break;
     132                 :       24813 :     case TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL:
     133                 :       24813 :         node.peerman->InitiateTxBroadcastToAll(wtxid);
     134                 :       24813 :         break;
     135                 :       10018 :     case TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST:
     136                 :       10018 :         return node.peerman->InitiateTxBroadcastPrivate(tx);
     137                 :             :     }
     138                 :             : 
     139                 :             :     return TransactionError::OK;
     140                 :             : }
     141                 :             : 
     142                 :        4107 : CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const Txid& hash, const BlockManager& blockman, uint256& hashBlock)
     143                 :             : {
     144         [ +  + ]:        4107 :     if (mempool && !block_index) {
     145                 :        4070 :         CTransactionRef ptx = mempool->get(hash);
     146         [ +  + ]:        4070 :         if (ptx) return ptx;
     147                 :          81 :     }
     148         [ +  + ]:          81 :     if (g_txindex) {
     149         [ +  + ]:          42 :         if (auto result{g_txindex->FindTx(hash)}) {
     150   [ +  +  +  + ]:          42 :             if (!block_index || block_index->GetBlockHash() == result->block_hash) {
     151                 :             :                 // Don't return the transaction if the provided block hash doesn't match.
     152                 :             :                 // The case where a transaction appears in multiple blocks (e.g. reorgs or
     153                 :             :                 // BIP30) is handled by the block lookup below.
     154         [ +  - ]:          39 :                 hashBlock = result->block_hash;
     155         [ +  - ]:          78 :                 return result->tx;
     156                 :             :             }
     157                 :          42 :         }
     158                 :             :     }
     159         [ +  + ]:          42 :     if (block_index) {
     160                 :          30 :         CBlock block;
     161   [ +  -  +  - ]:          30 :         if (blockman.ReadBlock(block, *block_index)) {
     162         [ +  + ]:          60 :             for (const auto& tx : block.vtx) {
     163         [ +  + ]:          58 :                 if (tx->GetHash() == hash) {
     164                 :          28 :                     hashBlock = block_index->GetBlockHash();
     165         [ +  - ]:          56 :                     return tx;
     166                 :             :                 }
     167                 :             :             }
     168                 :             :         }
     169                 :          30 :     }
     170                 :          14 :     return nullptr;
     171                 :             : }
     172                 :             : } // namespace node
        

Generated by: LCOV version 2.0-1